Web开发实战——spring 应用笔记(壹)

news/2024/7/5 19:34:22

Spring_前传(1)

软件环境:

  • IDE:IDEA
  • 插件:spring Initializer
  • mongoDB:v5.0.6
  • 驱动项目类型:校园网项目

使用Lombok简化领域对象

领域对象(Domain Object)也被称为实体类,代表了业务的状态,贯穿表现层、业务层和持久层,最终持久化到数据库,简单理解领域对象就是数据库的表所对应的类。

在校园网项目中,通知通告就是一个领域对象:

public class Notice 
{
    private String id;
    private String content;
    private Integer hit;
    private String title;
    private String createdTime;
    private String updatedTime;
    private String publisher;
    private String updateUser;}

Lombok是一个Java库,能自动插入编辑器并构建工具,简化Java开发。通过添加注解的方式,不需要为类编写getter或eques方法,同时可以自动化日志变量。

通过IDEA 插件初始化的springboot在Gradle的中可以看见已经自动添加了Lombok依赖下载:

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
    //HERE
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
	implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
	implementation 'org.mongodb:mongodb-driver-sync'
}

Lombok 注解地作用:

  • @Data注解的功能等同于**@Getter @Setter@RequiredArgsConstructor**

    所有的final属性以及标识为**@NonNull的属性@ToString** @EqualsAndHashCode这些注解的功能之和 ,注解在类上, 为类提供读写属性, 此外还提供了 equals()、hashCode()、toString() 方法

  • @Builder可以为类实现建造者模式 Builder详解 注释为你的类生成相对略微复杂的构建器API。

  • @Clearup在创建资源对象时省略close方法的调用

  • 使用valvar简化变量的定义

  • 使用**@Log**、@Log4j2等注解简化日志编写

当然不止这些注解,对于Lombok 最简单的理解就是通过注解来简化代码的书写

SpringBoot数据访问

Spring Data是一个总体项目,它以一致的编程模型为 大多数流行的数据访问技术(包括JPA,MongoDB, Redis,Cassandra,Solr和ElasticSearch)提供数据访问支持 :

本项目珠海要依赖于MongoDB所以主要讨论其与MongoDB的框架

在通过插件构造的框架中添加依赖实现其对MongoDB的支持。

	implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
	implementation 'org.mongodb:mongodb-driver-sync'

MongoDB与NoSQL

NoSQL(非关系数据库):

区别于传统的Mysql数据库其构建是基于非关系类型的。

优势:
可以支持超大规模数据存储,灵活的数据模型可以很好地支持Web2.0应用,具有强大的横向扩展能力。

劣势:
缺乏数学理论基础,复杂查询性能不高,大都不能实现事务强一致性,很难实现数据 完整性,技术尚不成熟,缺乏专业团队的技术支持,维护较困难等。

MongoDB就是典型的非关系数据库。由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。在高负载的情况下,添加更多的节点,可以保证服务器性能。

Mongodb的优点:

  • 易于使用
    面向文档的数据库使用更灵活的“文档”模型取代了“行”的概念,通过嵌入文档和
    数组,面向文档的方式可以仅用一条记录来表示复杂的层次关系,这与使用现代面向对 象语言的开发人员思考数据的方式非常契合

  • 易于扩展
    MongoDB 的设计采用了横向扩展,面向文档的数据模型使跨多台服务器拆分数据更加 容易,MongoDB
    会自动平衡跨集群的数据和负载,自动重新分配文档,并将读写操作 路由到正确的机器上

  • 功能丰富
    MongoDB 是通用型数据库,除了创建、读取、更新和删除数据外,它还提供了数据库 管理系统的常见功能和许多其他独特的功能

  • 性能卓越
    MongoDB在其 WiredTiger 存储引擎中使用了机会锁,以最大限度地提高并发和吞吐 量,它会使用尽可能多的
    RAM(内存)作为缓存,并尝试为查询自动选择正确的索引

MongoDB的存储解析:

面向文档的数据库,在MongoDB中基本的概念是文档、集合、数据库。

SQL术语/概念MongoDB术语/概念解释/说明
databasedatabase数据库
tablecollection数据库表/集合
rowdocument数据记录行/文档
columnfield数据字段
indexindex索引
table joins表连接,MongoDB不支持
primary keyprimary key主键,MongoDB自动将_id字段设置为主键

直观解释:

请添加图片描述

  集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System)中的表格。 集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格 式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。

更多内容:MongoDB

Spring Boot使用MongoDB

Spring 与 MongoDB的连接配置文件:

  对于需要连接的MongoDB,spring框架一般通过外部的配置文件,如 *.properties或者 *.yml文件来对应用进行配置。 * yml的语法更简洁,本课程推荐使用yml格式配置文件。

删除src/main/recources目录下idea自动创建 application.properties 配置文件,并在该目 录下新建 application.yml文件。

输入以下内容

spring:
    data:
        mongodb:
            uri: mongodb://localhost:端口/数据库名称

下面开始以实战形式建立连接与操作数据库显示在前台页面。

Spring Data实战

项目要求:

  1. 在项目中实现在页面中显示存储在MongoDB中的通知通告信息
  2. 参照Notice领域对象的实现,在项目顶层包下创建domain包,在domain包下创建校园网中的其它领域对象,包括Carousel(图片新闻)、Collaboration(校企合作)、Download(下载中心),Dynamic(学院动态)、Employment(就业情况),Graduate(校友风采),MemberStudent(团学工作)、Overview(学院概况)、TeacherResearch(教研情况)
  3. 参照NoticeRepository的实现,为每个领域对象创建对应的Repository接口
  4. 在项目顶层包下创建controller包,在controller包下创建通知通告信息的控制器类NoticeController(使用@Controller注解),在该类中创建处理通知通告信息列表、增加、删除、修改、查询(通告ID)请求的方法list、add、delete、update和find。
  5. 在resources目录的templates文件夹中创建Thymeleaf模板页面,实现通知通告信息的列表、增加、删除、修改、查询(通告ID)功能
  6. 在浏览器中测试项目。

  首先分析第一个是如何实现的:

在项目中实现在页面中显示存储在MongoDB中的通知通告信息

首先domain包中存在一个Notice类

package com.example.springdemo.domain;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Data
@Builder
//以上已经说过
@Document
//@Document注解是spring Data mongodb提供的一个注解,标注在实体类上,类似于hibernate的entity注解,标明由mongo来维护该表。把一个java类声明为mongodb的文档,可以通过collection参数指定这个类对应的文档。
public class Notice {
    @Id//自动生成的主键ID 主键,不可重复,自带索引,可以在定义的列名上标注,需要自己生成并维护不重复的约束。
    private String id;
    private String title;
    private String content;
}

  这里就是前面所说的领域对象的创建,满足这些就要考虑如何将领域对象传输入持久层,也就是如何传输到数据库中。要传输就要通过Spring Data MongoDB中Repository接口来实现传输功能。

  定义访问数据库的Repository接口,就需要继承 Spring Data Mongo 的 MongoRepository接口来实现其中的功能。

  对于本此时用的mongodb的专有接口实际上是多次继承而来的,其结构如下:
请添加图片描述

  • CrudRepository——Crud就是增、删、改、查的缩写,即Create、Read、Update、Delete 的首字母连在一起,该接口定义了基础的增、删、改、查操作
  • PagingAndSortingRepository——从命名上就可以看出是定义了分页和排序的操作,它继承 了CrudRepository之后又提供了分页和排序的操作
  • MongoRepository——和上面两个通用的接口不同,该接口是一个和数据库相关的接口,它继 承了PagingAndSortingRepository接口,同时封装了一些MongoDB特有的方法
  • 自定义的访问数据库的Repositoty接口,只要继承MongoRepository接口,甚至不需要添加任 何一行代码,就可以完成基本的增、删、改、查操作
  • 自定义Repository接口中,可以直接使用方法名关键字进行查询操作,例如:
List<Notice> findByTitleLikeOrderByUpdatedTimeDesc(String title);
编写针对Notice领域对象对应的Repository接口

  在项目的顶层包下新建一个repository的软件包,在该包中新建一个继承了 MongoRepository的NoticeRepository接口,代码如下所示:

package com.example.springdemo.repository;

import com.example.springdemo.domain.Notice;
import org.springframework.data.mongodb.repository.MongoRepository;

public interface NoticeRepository extends MongoRepository<Notice,String>
{

}

实际上只用继承本接口即可,不需要写具体的增删改查操作。

修改NoticeController类,使该类通过NoticeRepository访问数据库中的数据,代码如下所示:

/*
	@RestController注解,相当于@Controller+@ResponseBody两个注解的结合,返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面

	使用@Controller 注解,在对应的方法上,视图解析器可以解析return 的jsp,html页面,并且跳转到相应页面
若返回json等内容到页面,则需要加@ResponseBody注解
*/

@Controller
@AllArgsConstructor
public class NoticeController 
{
    private final NoticeRepository noticeRepository;
    @GetMapping("/notices")
    public String listNotice(Model model)
    {
        val list=noticeRepository.findAll();
        model.addAttribute("notices",list);
        return "test";
	}
}

在项目的顶层包中创建util软件包,在改包中新建InitDatabase类,该类在数据库中为集 合添加初始数据,代码如下所示:

package com.example.springdemo.util;

import com.example.springdemo.domain.Notice;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.stereotype.Component;
/*
@Controller 控制器(注入服务)
用于标注控制层,相当于struts中的action层

@Service 服务(注入dao)
用于标注服务层,主要用来进行业务的逻辑处理

@Repository(实现dao访问)
用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件

@Component (把普通pojo实例化到spring容器中,相当于配置文件中的 )

依赖注入(Dependency Injection):它是 Spring 框架核心 IOC 的具体实现。在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是代码中不可能出现没有依赖的情况。IOC 解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。那这种业务层和持久层的依赖关系,在使用 Spring 之后,就让 Spring 来维护了。简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。

@Component注解表明一个类会作为组件类,并告知Spring要为这个类创建bean。

*/
@Component
public class InitDatabase {
    @Bean//@Bean注解告诉Spring这个方法将会返回一个对象,这个对象要注册为Spring应用上下文中的bean。通常方法体中包含了最终产生bean实例的逻辑。我们在标有该注解的方法中定义产生这个bean的逻辑。下面就注册了多个bena对象到容器中
    public CommandLineRunner init(MongoOperations operations){
        return arg->{
            if(operations.findAll(Notice.class).isEmpty()){
                operations.insert(Notice.builder()
                        .title("title1")
                        .content("content1").build());
                operations.insert(Notice.builder()
                        .title("title2")
                        .content("content2").build());
                operations.insert(Notice.builder()
                        .title("title3")
                        .content("content3").build());
            }
        };
    }
}

  • 参照Notice领域对象的实现,在项目顶层包下创建domain包,在domain包下创建校园网中的其它领域对象,包括Carousel(图片新闻)、Collaboration(校企合作)、Download(下载中心),Dynamic(学院动态)、Employment(就业情况),Graduate(校友风采),MemberStudent(团学工作)、Overview(学院概况)、TeacherResearch(教研情况)
  • 参照NoticeRepository的实现,为每个领域对象创建对应的Repository接口

这个就很简单不再赘述:直接一个一个创建就ok。和Notice只是名字有修改。
请添加图片描述

  • 在项目顶层包下创建controller包,在controller包下创建通知通告信息的控制器类NoticeController(使用@Controller注解),在该类中创建处理通知通告信息列表、增加、删除、修改、查询(通告ID)请求的方法list、add、delete、update和find。
  • 在resources目录的templates文件夹中创建Thymeleaf模板页面,实现通知通告信息的列表、增加、删除、修改、查询(通告ID)功能

(1)@RequestMapping

  @RequestMapping如果没有指定请求方式,将接收Get、Post、Head、Options等所有的请求方式.

(2)@GetMapping

  @GetMapping是一个组合注解,是@RequestMapping(method = RequestMethod.GET)的缩写。该注解将HTTP Get 映射到 特定的处理方法上。

(3)@PostMapping

  @PostMapping是一个组合注解,是@RequestMapping(method = RequestMethod.POST)的缩写。get方式的安全性较Post方式要差些,包含机密信息的话,建议用Post数据提交方式;(请求的结果有持续性的副作用,例如,数据库内添加新的数据行。)

(4)@PutMapping

  和PostMapping作用等同,都是用来向服务器提交信息。如果是添加信息,倾向于用@PostMapping,如果是更新信息,倾向于用@PutMapping。两者差别不是很明显。

  由此可见对于浏览器发来的请求POST比较合适作为传递内容方式。对于后端首先要解决向前端传输显示内容:

  通过 NoticeRepository 类和 @GetMapping("/notices") 来实现相应页面的请求并将内容显示,通过NoticeRepository 类获取数据库内容并将数据库内容放到 list 里面再通过html中标记的 notices 来实现显示和后端的链接。

private final NoticeRepository noticeRepository;
@GetMapping("/notices")
public String list(Model model)
{
    val list=noticeRepository.findAll();
    model.addAttribute("notices",list);
    return "listNotice";
}

  在前端我们通过 data-th-each= 标签遍历notices的内容并将notices的内容通过table标签完全的显示出来,但是前端和后端的变量是如何通过一个相同的变量连接在一起的呢?这是spring框架所做的工作,只要理解,前后端能通过相同的变量连接在一起。

<table style="text-align:left" >
    <th style="text-align:left">
    <td style="width:400px;">编号</td>
    <td style="width:200px">标题</td>
    <td style="width:200px">内容</td>
    </th>
	<!--连接前后端的notices-->
    <tr data-th-each="item:${notices}" >
        <td style="width:400px" data-th-text="${item.id}"></td>
        <td style="width:200px" data-th-text="${item.title}"></td>
        <td style="width:200px" data-th-text="${item.content}"></td>
        <td style="width:200px">
        </td>
    </tr>
</table>

  题目要求还有其他四种操作方式,那是如何让后端识别不同的操作呢?这就需要通过在表单中加入一个隐藏的参数:_method,设置value值来传递信息

 <input type ="hidden" name="_method" value="delete" />

我们通过< form > 和< input >标签来向后端传输数据,详细解释看注释:

<!--from标签指定了action和请求的办法,这里使用的是POST请求。-->
<form action="/notices" method="POST">
<!--input标签指定了传输的数据类型,使用隐式方便向后端传输数据,在后端直接在方法里填入参数和name值相同的变量就可直接获取-->
    <input type ="hidden" name="_method" value="delete" />
    <!--获取用户输入的id号码-->
       id:<input type="text" name="id">
    <br>
    <!--对产生的按钮设置显示值-->
    <input type="submit" value="Submit">
</form>

  后端就直接在方法的形参中获取同名的参数内容即可:

 @PostMapping("/notices")
    public String postcallback
        (Model model,String _method,String id,String content,String title)
        //通过隐式参数获取想要的信息
    {
        if(_method.equals("delete"))
        {
            Notice deletn =null;
            if (!id.equals(""))
                deletn = noticeRepository.findById(id).get();
            if (deletn != null)
                noticeRepository.delete(deletn);
        }
        else if (_method.equals("add"))
        {
            if (!title.equals("")  && !content.equals("") )
                noticeRepository.insert(Notice.builder()
                                .title(title)
                                .content(content)
                                .id(null).build());
        }
        else if (_method.equals("find"))
        {
            if (!id.equals("") )
                 model.addAttribute("findnotices",noticeRepository.findById(id).get());
        }
        val list=noticeRepository.findAll();
        model.addAttribute("notices",list);
        return "listNotice";
    }

补充:HTML的标签定义

< table >标签定义 HTML 表格

< tr > 元素定义表格行,< th > 元素定义表头,< td > 元素定义表格单元。

更复杂的 HTML 表格也可能包括 < caption >、< co l>、< colgroup >、< thead >、< tfoot> 以及 < tbody> 元素。

< form > 标签用于为用户输入创建 HTML 表单。

表单能够包含 input 元素,比如文本字段、复选框、单选框、提交按钮等等。

表单还可以包含 menus、textarea、fieldset、legend 和 label 元素。

表单用于向服务器传输数据。

< input > 标签用于搜集用户信息。

根据不同的 type 属性值,输入字段拥有很多种形式。输入字段可以是文本字段、复选框、掩码后的文本控件、单选按钮、按钮等等。

补充:一些报错的解决办法。

运行后报错:

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2022-03-06 12:11:08.452 ERROR 18420 --- [  restartedMain] o.s.boot.SpringApplication   : Application run failed
java.lang.IllegalStateException: Failed to execute CommandLineRunner。

解决办法:

找到MongoDB的安装目录:在栏中输入CMD打开CMD
请添加图片描述

输入以下命令:

mongod --dbpath 数据库路径

  如图: 数据库不一定和Mong0DB安装的位置相同,需要找到自己安装的位置
请添加图片描述

  输入后可以看见开始运行其服务:

请添加图片描述

  打开COMPASS 直接点击链接,连接后可以看见正常运行:

请添加图片描述

打开后可以看见对应数据:
请添加图片描述


http://www.niftyadmin.cn/n/1102376.html

相关文章

Spark快速大数据分析——Scala语言基础(壹)

Spark快速大数据分析——Scala语言基础&#xff08;壹&#xff09; 文章目录Spark快速大数据分析——Scala语言基础&#xff08;壹&#xff09;前记Scala的历史环境搭建&#xff1a;1、SBT构建工具和REPL&#xff1a;2、使用IDE&#xff1a;Scala 入门&#xff1a;一点点补充&a…

项目风险管理落地

发现很多做项目的同学&#xff0c;会忽略对项目风险的管理&#xff0c;以至于成为项目的救火队长&#xff0c;处理各种应急事件。为了让项目开展更顺畅&#xff0c;避免出现项目既乱又累的问题&#xff0c;不应以战术上的勤奋&#xff0c;掩盖战略上的懒惰&#xff0c;梳理总结…

2018年OpenStack用户调查报告出炉:Kubernetes仍居首

这份报告来自由OpenStack基金会发起的全球OpenStack用户调查项目&#xff0c;汇总了2017年8月至2018年8月期间1483个已完成的调查&#xff08;代表858个部署&#xff0c;来自441个独特的用户组织&#xff09;。作为第11次OpenStack用户调查&#xff0c;本次调查重点关注了全球用…

python爬虫笔记-day5

mongodb插入数据db.collecion.insert({}) 插入数据&#xff0c;_id存在就报错 db.collection.save({}) 插入数据&#xff0c;_id存在会更新 mongodb的更新操作db.test1000.update({name:"xiaowang"},{name:"xiaozhao"})把name为xiaowang的数据替换为{name:…

深入解析webpack 插件html-webpack-plugin

这个插件用来简化创建服务于 webpack bundle 的 HTML 文件&#xff0c;尤其是对于在文件名中包含了 hash 值&#xff0c;而这个值在每次编译的时候都发生变化的情况。你既可以让这个插件来帮助你自动生成 HTML 文件&#xff0c;也可以使用 lodash 模板加载生成的 bundles&#…

zabbix之 zabbix server 跟 agent 更换ip地址

描述: zabbix server端跟agent端更改 ip 。 改完之后&#xff0c;相应配置文件 &#xff08;zabbix_agentd.conf、zabbix_server.conf&#xff09;的ip也进行了替换 但是依旧报错&#xff0c;如图 解决&#xff1a; &#xff08;PHP的配置文件没有更新&#xff09; vi /home/bm…

Android开发笔记——快速入门(壹)[系统架构和Android Studio安装]

Android开发笔记——快速入门&#xff08;壹&#xff09;[系统架构和Android Studio安装] 文章目录Android开发笔记——快速入门&#xff08;壹&#xff09;[系统架构和Android Studio安装]软件环境&#xff1a;Android的系统架构Linux 内核硬件抽象层 (HAL)Android Runtime原生…

暴力破解和彩虹表攻击的区别与联系

一、暴力破解 暴力破解可分为纯粹式暴力破解和字典式暴力破解&#xff0c;一般暴力破解工具都会同时实现这两种暴力破解方式。 注意暴力破解不只是指解猜用户名密码&#xff0c;解猜压缩文件解压口令、猜解word文档读写口令、猜解系统后台管理地址等只要是猜的都属于暴力破解。…