工欲善其事必先利其器。
码字不易,喜欢就点个关注❤,持续更新技术内容。
1 Web架构技术基础
BS架构:Browser/Server,浏览器/服务器架构模式
CS架构:Client/Server,客户端/浏览器架构模式
1.1 两种架构原理的对比
C/S架构主要的特点是交互性强,具有安全访问模式,网络流量低,响应速度快,因为客户端负责大多数业务逻辑和UI演示,所以也被称为胖客户端,C/S架构的软件需要针对不同操作系统开发不同版本的软件。
随着互联网的兴起,C/S架构不适合Web,最大的原因就是Web应用程序的修改和升级非常迅速,而C/S架构需要每个客户端逐个升级桌面App,因此,Browser/Server模式开始流行,简称B/S架构。
B/S架构的主要特点是分散性高、维护方便、开发简单、共享性高、总拥有成本低。在B/S架构下,客户端只需要浏览器,应用程序的逻辑和数据都存储在服务器端。浏览器只需要请求服务器,获取Web页面,并把Web页面展示给用户即可。
1.2 Java环境配置
Java开发工具包
JDK就是Java开发工具包。它是一个java程序的开发环境,提供了开发、测试和部署Java应用程序所需的工具和库。JDK包括Java运行环境(JRE),用于运行Java应用程序,以及在开发过程中使用的额外工具和实用程序。
下载JDK工具安装包:www.oracle.com/java/techno...
双击下载的JDK,按照提示进行默认按照即可,注意安装路径不能出现中文或空格。
打开"高级系统设置"中的"环境变量"选项,在环境变量中新建环境变量JAVA_HOME,值就是JDK的安装路径,然后再在Path中编辑环境变量,因为最终用到的是路径下的bin目录,所以新建Path:%JAVA_HOME%/bin。
配置环境变量后可以打开命令行窗口输入java -version查看配置的JDK版本。
Java程序编辑工具
InterlliJ IDEA开发工具
下载地址:www.jetbrains.com/idea/downlo...
1.3 项目管理工具
下载安装
Maven是一个项目管理工具,可以对Java项目进行自动化的构建和依赖管理。如项目的编译、运行和打包都可以通过maven来完成,其次可以通过maven的核心配置文件pom.xml中记录的依赖目标自动地从远程仓库中下载依赖包。
maven地作用可以分为三类:
项目构建:提供标准的、跨平台地自动化构建项目的方式。
依赖管理:方便快捷的管理项目依赖的资源包,避免资源间的版本冲突等问题。
统一开发结构:提供标准的、统一的项目开发结构。
下载安装
官方下载地址:maven.apache.org/download.cg...
将压缩包解压安装到任意目录即可,注意安装路径不能出现中文或空格。
IDEA中本身自带默认的maven,不是特别好用,有时需要对一些配置进行修改,所以更倾向于自己下载安装maven进行配置。
Maven仓库
运行Maven仓库的时候,Maven所需要的任何构件都是直接从本地仓库获取的。如果本地仓库没有,它会首先尝试从远程仓库中下载构件到本地仓库中。
本地仓库配置
修改maven安装包中的conf/settings.xml文件,指定本地仓库位置。不指定的话默认本地仓库是C盘的用户目录下的.m2文件夹下。
镜像地址配置
maven默认连接的远程仓库位置并不在国内,因此有时候下载速度非常慢,我们可以配置一个国内站点镜像网址,可用于加速下载资源。同样的,在settings.xml文件中标签内添加镜像:
xml
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
新建maven项目
这里设置项目的名称和地址,以及项目坐标的GAV(保证项目唯一性),测试用坐标不配也行。
进入编辑环境中,打开设置将idea默认配置的maven改为自己下载的maven。第一是maven解压的路径,第二是settings.xml配置文件位置,点击覆盖,选择对应的配置文件。最后是自己创建和配置的本地仓库位置。
2 SpringBoot介绍与项目创建
2.1 SpringBoot介绍
SpringBoot是由Pivotal团队提供的基于Spring的全新框架,旨在简化Spring应用的初始搭建和开发过程。Java开发企业级应用一般会涉及到三个框架,Spring、SpringMVC和Mybatis,也就是SSM,其开发特点是配置特别繁琐,涉及大量的xml文件。
SpringBoot的设计目标就是使开发者能够更轻松地创建独立的、基于Spring的应用程序,而无需过多的配置。尽可能地简化应用开发的门槛,让应用开发、测试、部署变得更加简单。
SpringBoot特点:
自动配置:遵循"约定优于配置的原则",只需要很少的配置或使用默认的配置。
嵌入式服务器:提供内嵌的Tomcat、Jetty服务器。
起步依赖:提供定制化的启动器Starters,简化Maven配置,开箱即用。
简化的配置:Spring Boot采用了简化的配置方式,使用了属性文件(如application.properties或application.yml)来配置应用程序。这种方式使得配置更易于理解和管理。
Actuator:Actuator可以提供对应用程序的运行时指标、健康检查、日志记录、性能监视等功能,对于应用程序的运维和监控非常有帮助。
2.2 快速创建SpringBoot项目
利用IDEA提供的Spring Initializr通过SpringBoot框架搭建应用程序。
GAV:
Group:一般输入公司域名的倒置
Artifact:项目名称
通过安装Web项目相关的依赖,如SpringMVC。
有时候进去后发现maven插件的依赖飘红,这是因为springboot与maven插件版本冲突问题,springboot版本与maven从父工程parent中引入的默认版本发生冲突,修改springboot版本或者maven版本即可。但是有时候可能只是IDEA的问题,重启一下就好。
以下是一些项目结构中较重要的目录文件,其中static和templates目录文件在前后端混合开发时会使用,在前后端分离项目中就不需要了。
2.3 开发环境热部署
在实际的项目开发调试过程中会频繁地修改后台类文件,导致需要重新编译、重新运行,整个过程非常麻烦,影响开发效率。SpringBoot提供了spring-boot-devtools组件,devtools会监听classpath下的文件变动,触发Restart类加载器重新加载该类,从而实现类文件和属性文件的热部署。使得无需动手重启SpringBoot应用即可重新编译、启动项目,大大缩短启动的时间。并不是所有的更改都需要重启应用,如静态资源、视图模板的修改可通过设置spring.devtools.restart.exclude属性来指定一些文件或目录的修改不用重启应用。
首先在pom.xml中添加spring-boot-devtools的依赖坐标,然如果需要进一步配置可以在application.propertie配置文件中添加配置信息,如设置spring.devtools.restart.exclude属性来指定一些文件或目录的修改不用重启应用。
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>2.4.0</version>
</dependency>
然后打开Settings页面在左边栏找到Buid,Execution,Deployment下的Compile,勾选Build project automatically。确认后再按"Ctrl+Shift+Alt+/"快捷键弹Maintenance维护页面,单击Registry,勾选compile.automake.allow.when.app.running复选框,在新版里此选项放在了settings下advanced settings中。做完后若在IDEA中修改代码,则项目会自动重启。
2.4 系统配置
在application.properties中可以对springboot项目信息进行配置,如服务器端口、数据库连接等配置,以键值对的方式进行配置,如:
properties
server.port=7777
3 Controller
控制器Controller基于Servlet服务程序,也可以说Controller类似于Servlet。Controller和Servlet都是用来接收客户端发送的请求消息request,以及返回给客户端响应消息response的服务程序。运行在容器中(如Tomcat、Jetty服务器等),容器会根据请求路径将其分配给对应的Controller或者Servlet进行处理,后将处理结果作为响应消息发送回客户端。
3.1 Web入门
SpringBoot将传统Web开发的mvc、json、tomcat等框架整合,提供了spring-boot-starter-web组件,简化了Web应用配置。
创建SpringBoot项目勾选SpringWeb选项后,会自动将spring-boot-starter-web组件加入到项目中。
spring-boot-starter-web启动器主要包括web、webmvc、json、tomcat等基础依赖组件,作用是提供Web开发场景所需的所有底层依赖。
webmvc为Web开发的基础,json为json数据解析组件,tomcat为自带的容器依赖。
3.2 控制器
SpringBoot提供了@Controller和@RestController两种注解来标识此类负责接收和处理HTTP请求。如果请求的是页面和数据,使用@controller注解;如果只是请求数据,则使用@RestController注解即可。@Controller一般在前后端混合开发中使用,需要同时响应页面和数据。而@RestController在前后端分离开发中使用,因为页面都交给了前端,后端只需要响应相关数据。所以主要使用的还是@RestController。
@RestController的用法
默认情况下,@RestController注解会将响应的对象数据转换为json格式。如以下返回一个user对象,该对象会以json字符串的形式响应给前端处理。
java
@RestController
public class HelloController {
@GetMapping("/user")
public User getUser(){
User user = new User();
user.setName("Bree");
user.setPassword("123");
return user;
}
}
3.3 路由映射
@RestController注解主要负责URL的路径映射。它可以添加在Controller类或者具体的方法上。如果添加在Controller类上,则这个Controller中的所有路由映射都会加上此映射规则,如果添加在方法上,则只对当前方法生效。
@RequestMapping注解包含很多属性参数来定义HTTP的请求映射规则。常用的 属性如下:
- value:请求URL的路径,支持URL模板、正则表达式。
- method:HTTP请求方法,如GET、POST、PUT、DELETE。
- consumes:请求的媒体类型(Content-Type),如application/json。
- produces:响应的媒体类型。
- params,headers:请求的参数和请求头的值。
java
@RestController
public class HelloController {
@RequestMapping(value="/getData", mathod = RequestMethod.GET)
public String getData(){
return "Hello!";
}
}
Method匹配也可以使用@GetMapping、@PostMapping等注解代替。
3.4 参数传递和数据响应
@RequestParams
将请求参数绑定到控制器的方法参数上,接收的参数来自HTTP请求体或请求URL的QueryString,当请求的参数名称与Controller的业务方法参数名称一致时,RequestParams可以省略。
可以向服务端传递参数的请求路径为:http://localhost:7777/getData?name=bree&number=1
java
@RestController
public class HelloController {
@GetMapping("/getData")
public String getData(String name, String number){
return "Hi "+name+", your number is: "+number;
}
}
还可以定义POST请求接口,并且接收参数。
java
@RestController
public class HelloController {
@PostMapping("/postTest")
public String postTest(String name, String number){
return "Hi "+name+", your number is "+number;
}
}
但地址栏只能发送GET请求,不能发送POST请求。可以下载一个调试工具,如Postman、Apipost等。如下图,定义发送的参数数据,或者也可以通过我用Postman向启动的服务端发送请求后得到正常响应,表示服务端已接收到传递的参数,当然,POST请求也可以通过在"?"后传递参数。
@RequestBody
接收的参数是来自requestBody中,即请求消息中的请求体(消息体)。一般用于处理application/json、application/xml编码类型的数据。
JSON对象:Javascript Object Notation,JavaScript对象标记语言,通过JavaScript对象标记法书写的文本。语法简单,结构简明,多用于作为数据载体,在网络中进行数据传输。
定义:var jsonStr = '{ "key01": "Bree", "key02": 21, "arr01": ["男", "女"] }'
JSON字符串转化为JS对象:var jsObj = JSON.parse(jsonStr); JS对象转化为JSON字符串:var jsonStr = JSON.stringify(jsObj);
以下定义POST请求接口,并且接收的参数类型为User类。
java
@RestController
public class HelloController {
@PostMapping("/postTest1")
public String postTest(@RequestBody User user){
System.out.println(user);
return "Post请求发送成功";
}
}
可以看到,通过Postman向服务端发送Post请求,并传递application/json类型数据:json对象。如图成功响应,后端也成功接收到json数据并转换为User类对象打印出来:
@PathVaraible
后面开发RESTful接口时可以可以作为控制器中处理方法的参数,接收处理动态的URL,URL中值。
3.5 Multipart
表单的编码类型enctype属性规定在发送到服务器之应该如何对表单数据进行编码,也就是内容类型content-type。当表单的enctype="application/x-www-form-urlencoded"(默认)时,form表单中的数据格式为:key=value&key=value。
当表单的编码类型enctype="multipart/form-data"时,一个请求中,如Post请求中可以给服务器发送多种类型的数据,可以是文本,也可以是图片或者音视频等等。其传输数据形式如下:
css
----boundary----
Content-Disposition: form-data; name="foo"
bar
----boundary----
Content-Disposition: form-data; name="baz"
The first line.
The second line.
----boundary----
在这种表单提交的情景下,我们不需要手动设置Content-Type,不用去关系请求消息中的数据是如何排列的,也不需要知道boundary如何分隔,这些都有浏览器来自动完成。
SpringBoot文件上传
Springboot工程嵌入的tomcat限制了请求中的文件大小,每个文件的配置最大为1M,单次请求的文件总数不能大于10M。要更改这个默认值需要在配置文件中加入两个配置:
properties
spring.servlet.mutipart.max-file-size=10M
spring.servlet.mutipart.max-request-size=10M
#保存上传的文件到指定目录下
spring.web.resource.static-locations=/upload/
当表单的enctype="multipart/form-data"时,可以使用MultipartFile类接收上传的文件数据,再通过transferTo方法将其写到磁盘中:
java
@RestController
public class FileController {
@PostMapping("/upload")
public String up(String name, MultipartFile f, HttpServletRequest request) throws Exception {
System.out.println(name);
System.out.println(f.getOriginalFilename());
System.out.println(f.getContentType());
System.out.println(System.getProperty("user.dir"));
String path = request.getServletContext().getRealPath("/upload");
System.out.println(path);
saveFile(f, path);
return "上传成功";
}
public void saveFile(MultipartFile f, String path) throws Exception {
File dir = new File(path);
if(!dir.exists()){
dir.mkdir();
}
File file = new File(path+f.getOriginalFilename());
f.transferTo(file);
}
}
3.6 拦截器
拦截器再Web系统中非常常见,对于某些全局统一的操作,我们可以把它提取到拦截器中实现。拦截器其实就是一个servlet接口,服务器会根据请求的URL先找到对应的拦截器,经过判断是否允许进行下一个程序。总结起来,拦截器大致有以下几种使用场景。
- 权限检查:如登录检测,进入处理程序检测是否登录,如果没有则返回登录页面。
- 性能监控:有时系统在某段时间莫名其妙很慢,可以通过拦截器在进入程序之前记录开始时间,在处理完后结束时间,从而得到该请求的处理时间等情况。
- 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有提取Local、Theme信息等,只要是多个处理程序都需要的 ,即可以使用拦截器实现。
SpringBoot定义了HandlerInterceptor接口来实现自定义拦截器的功能。HandlerInterceptor接口定义了preHandle、postHandle和afterHandle三种方法,通过重写这三种方法实现请求前、请求后等操作。
拦截器定义,新建登录拦截器类,实现HandlerInterceptor的preHandle方法:
java
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
if(true){
System.out.println("进入下一个程序");
return true;
}else{
System.out.println("不允许进入下一个程序");
return false;
}
}
}
拦截器也需要通过配置注册到服务器中,类似于定义了一个Servlet类,然后在web.xml中添加Servlet配置信息,便于服务器读取配置的servlet对应的信息数据,当这一步骤没有出错并且完成之后,项目才能正常地被启动起来:
java
@Configuration
public class WebConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/user/**")
}
}
其中:
addPathPatterns方法定义拦截的路由。
excludePathPatterns定义排除某些地址不被拦截。
- 添加的一个拦截器没有addPathPattern任何一个url则默认拦截所有请求。
- 添加excludePathPatterns可以放过对应地址的请求。
总的来说,注册拦截器时设置对应地址的拦截,只要是对路由下地址的请求都会进入拦截器。如不设置对应地址的拦截,所有请求都会进入拦截器。当然可以添加excludePathPatterns可以放过对部分地址的请求。
4 REST风格
4.1 REST风格介绍
REST即表述性状态传递(英文:Representational State Transfer,简称REST)。REST中,所有资源以一种状态(表现形式)保存在服务器端中。因此,如果客户端想要操作服务器,需要通过某种手段,如HTTP操作,将服务器中的资源状态在表现层上进行转换,这就是"表述性状态转化"。
如果一个互联网软件服务架构符合REST风格,则称为Restful,所以Restful指的是一种设计风格,而不是一种技术。客户端和服务端交互中基于这种风格原则设计出的Web api更加简洁,更有层次。
在Web api开发中,客户端使用GET获取资源,POST新建资源,PUT更新资源,DELETE删除资源,通过这些操作转换资源的表现形式来实现服务端请求操作。
SpringBoot提供的spring-boot-starter-web组件完全支持开发RESTful api,提供了与REST操作方式对应的注解:
- @GetMapping:处理GET请求,获取数据。
- @PostMapping:处理POST请求,新增数据。
- @PutMapping:处理PUT请求,更新资源。
- @DeleteMapping:处理DELETE请求,删除资源。
- @PatchMapping:处理PATCH请求,用于部分更新资源。
符合RESTful规范的Web api需要具备如下两个关键特性:
安全性:安全的请求操作期望不会产生任何副作用,也就是如通过GET操作获取资源时不会改变资源本身,也不会引起服务器状态的改变。
幂等性:在数学上幂等性是指N次变换和 一次变换相同,幂等的方法保证了进行一个请求和重复一次请求的效果相同。
总之简单地说,一个HTTP请求除了利用url标志目标资源以外,还需要通过HTTP Method指定针对该资源表现形式转换的操作类型。
在RESTful架构中,利用URL标志目标资源,所以说最常见的一种设计错误,就是URI包含动词。因为"资源"表示一种实体,所以应该是名词,URI不应该有动词,动词应该放在HTTP协议中。
示例:
HTTP Methods | 接口地址 | 接口说明 |
---|---|---|
POST | /user | 创建用户 |
GET | /user/id | 根据id获取查询某一用户 |
PUT | /user | 更新用户 |
DELETE | /user/id | 根据id删除某一用户 |
4.2 SpringBoot实现RESTful API
java
@RestController
public class RestfulApi {
@Autowired
UserMapper userMapper;
@GetMapping("/user/{id}")
public String getUserById(@PathVariable int id){
User user = userMapper.selectById(id);
return "根据id获取用户:"+user;
}
@PostMapping("/user")
public String addUser(User user) {
int insert = userMapper.insert(user);
return "添加用户"+user;
}
@PutMapping("/user")
public String updateUser(User user) {
userMapper.update(user,null);
return "更新用户"+user;
}
@DeleteMapping("/user/{id}")
public String deleteUser(@PathVariable int id){
int i = userMapper.deleteById(id);
return "根据id删除用户";
}
}
数据库初始表:
a.发送根据id查询获取用户的请求:
b.发送创建用户的请求:
c.发送未指定id进行密码更新的请求,会将所有用户的密码进行更新:
d.发送根据id删除用户的请求:
5 Swagger生成WebAPI文档
Swagge是一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务,是非常流行的API表达工具。同时Swagger还能够自动生成完善的RESTful API文档页面,并根据后台代码的修改同步更新。
在SpringBoot项目中集成Swagger非常简单,只需在项目中引入springfox-swagger2和springfox-swagger-ui两个依赖即可:
xml
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
通过配置类配置Swagger:
java
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.bree"))
.paths(PathSelectors.any()).build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("Swagger2")
.description("学习Swagger2")
.build();
}
}
注意事项:SpringBoot2.6.x以后的版本与Swagger有版本冲突问题,需要在application.properties中加入以下配置:
properties
spring.mvc.pathmatch.match-strategy=ant_path_matcher
启动项目访问http://localhost:xxxx/swagger-ui.html,即可打开自动生成的可视化测试文档页面。
Swagger提供了一系列注解来描述接口信息,包括接口说明、请求方法、请求参数、返回信息等。如可以在接口方法上添加@ApiOperation描述接口的功能:(其他的注解可以参考文档)
6 MybatisPlus
介绍完如何接收和处理前端各种请求并响应结果后,接下来就是如何与数据库打交道了。如:如何通过Mybatis和MybatisPlus对数据库表的进行各种操作(CRUD),并了解其中的原理。
6.1 ORM介绍
ORM(Object Relational Mapping,对象关系映射)是为了解决面向对象与关系数据库存在的互不匹配现象的一种技术。通过使用描述对象和数据库之间映射的元数据将程序中的对象自动持久化到关系数据库中。ORM框架的本质是简化编程中操作数据库的编码。
6.2 MybatisPlus
Mybatis是一款优秀的数据持久层ORM框架,被广泛地应用于应用系统。Mybatis能够非常灵巧地实现动态SQL,可以使用xml或注解来配置和映射原生信息,能够轻松地将Java的POJO(Plain Ordinary Java Object,普通Java对象)与数据库中的表和字段进行映射关联。
Mybatis提供基于JDBC的数据库连接。通常使用数据库连接池(如德鲁伊)来管理数据库连接的复用和性能优化。
在结果映射阶段,MyBatis可以根据Java类的定义和映射文件中的配置,使用反射技术动态地创建对象实例并设置属性值,将查询结果映射为Java对象。
Mybatis-Plus是Mybatis的增强工具,在Mybatis的基础上做了简化和增强。
首先在pom.xml中添加mybatis-plus的依赖坐标,其中下载mybatis-plus依赖的同时也对mybatis的依赖进行了引入,后续也可以进行mybatis开发。我要连接的数据库是sqlserver,所以添加上sqlserver连接驱动的依赖坐标。以及管理数据库连接的复用和性能优化的连接池德鲁伊:(注意druid版本)
xml
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc4</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
然后在application.properties中配置数据库连接以及数据源的相关信息:
- 我们要清楚的就是Spring Boot默认的数据源是org.apache.tomcat.jdbc.pool.DataSource,
- 实际开发中我们可能需要使用我们比较熟悉的数据源或者性能比比较高的数据源,
- spring.datasource.type属性的存在能够使我们快速的指定需要的数据源,比如Druid。
properties
#指定我们需要的数据源
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# sqlServer链接驱动
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
# 指定Sqlserver服务端口和数据库
# 可以新建查询执行exec sys.sp_readerrorlog 0,1,'listening';查看端口,也可以在SQLServer配置管理器修改
# Mysql可以运行show variables like 'port';语句查看
spring.datasource.url=jdbc:sqlserver://localhost:1434;DatabaseName=xxx
spring.datasource.username=xxx
spring.datasource.password=xxx
最后在启动类中添加@MapperScan注解,配置的包路径,扫描所有mapper接口,注册到Spring容器中,为后续Bean初始化做准备:
java
@SpringBootApplication
@MapperScan("com.xxx.mapper")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
6.3 Mybatis注解开发
所有的依赖下载和相关配置完成后,就可以通过Mybatis和MybatisPlus对数据库表的进行各种操作了(CRUD)。
在进行Mybatis开发我们先了解Mybatis的开发。以下是常用的Mybatis注解:
注解 | 功能 |
---|---|
@insert | 实现插入语句的发送 |
@Update | 实现更新语句的发送 |
@Delete | 实现删除语句的发送 |
@Select | 实现查询语句的发送 |
@Results | 封装多个结果集 |
@Result | 实现查询结果集的封装 |
@One | 实现一对一结果集封装 |
@Many | 实现一对多结果集封装 |
查询返回用户
定义一个与数据库表对应的类,其中的成员变量与数据库表中的字段一一对应。
java
@TableName("t_user")
public class User {
//主键建议用Integer
@TableId(type=IdType.AUTO)
private Integer id;
private String uname;
private String pwd;
private String birthday;
Setter and Getter;
toString(){...};
}
在mapper包中新建用户接口,添加@Mapper注解,使得@MapperScan可以扫描到,注册到Spring容器中,当使用的时候会动态初始化出接口实现类对象,我们要使用接口中定义操作方法时只需进行注入调用即可。
java
@Mapper
public interface userMapper {
@Select("select * from user")
//注意一定要写映射的类,如果映射的类的类名与数据库表不一致,
//需要在类的定义上添加@TableName("表名")指定该类要映射的表。
//且在MybatisPlus注解开发中,自动生成sql会查询所有类下的成员,
//所以类中的成员变量一定要与数据库表字段一一对应。
public List<User> queryUser();
}
在控制器中注入mapper中的接口UserMapper,初始化出接口实现类对象userMapper,并调用其中的操作方法,客户端发送请求,查询返回并成功响应给前端:
java
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/getUser")
public String getUser(){
List<User> users = userMapper.queryUser();
users.forEach(s -> System.out.println(s));
return "请求成功:"+ users;
}
}
查询返回结果:
添加用户
java
@Mapper
public interface UserMapper {
//在Mybatis注解开发中,手动写sql语句可以只查询或插入部分字段,
//只需要保证查询或插入的字段与类中成员变量一一对应即可。
@Insert("insert into t_user values(#{uname}, #{pwd}, #{birthday})")
public int insertUser(User user);
}
java
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@PostMapping("/insertUser")
public String insertUser(User user){
int i = userMapper.insertUser(user);
if (i > 0) {
return "插入成功";
}else {
return "插入失败";
}
}
}
插入结果:
6.4 MybatisPlus注解开发
Mybatis-Plus是Mybatis的增强工具,在Mybatis的基础上做了简化和增强。但当关系映射的实现比较复杂时,如进行多表查询时,就需要通过Mybatis手动配置相关的注解和写sql语句来完成。但在大多数情况MybatisPlus还是相当快捷、方便和实用的。
常用注解:
- @TableName(value="t_xxx"):表名注解,如果类名与表名不一致,可以指定该类映射的数据库表。
- @TableField(exist = boolean / "表名"):字段注解(非主键),第一个属性是否映射为数据库表字段,第二个属性是如果类的属性与表的字段不一致,可以指定该类的属性映射的数据库表中的字段。
- @TableId(type=IdType.AUTO):主键注解,说明数据库主键自增,插入时回显主键。
- @Version:乐观锁注解、标记在字段上。
- @EnumValue:普通枚举类注解(注解在枚举字段上)。
以上只是描述了部分常用注解的部分属性,还有很多的其他注解功能可以参考文档开发。
查询用户
在MybatisPlus开发中,查询用户相当简单,只需让原用户类对应的接口继承MybatisPlus的mapper下的BaseMapper接口,注意添加泛型:
java
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
然后在UserController中,就可以直接调用BaseMapper接口中定义的自动生成sql操作的指定方法进行查询了:
java
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/getUser")
public String getUser(){
List<User> users = userMapper.selectList(null);
users.forEach(s -> System.out.println(s));
return "请求成功:"+ users;
}
}
查询返回结果:
条件查询
因为MybatisPlus不用手动写sql查询语句,所有当需要进行条件查询时,要通过条件构造器QueryWrapper进行条件的定义,然后传入给查询方法,查询方法会根据传入的条件对象自动生成sql查询语句:
注意:因为不用手动写sql后,生成的sql查询语句会涉及到类中所有属性,若其中一个属性不存在于表中,mysql会报未知字段的错误。需要在对应类中属性上添加@TableField(exist = false)注解。
java
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/getUser")
public String getUser(){
// 初始化条件对象
QueryWrapper<User> queryWrap = new QueryWrapper();
queryWrap.eq("uname","Mingwan");
List<User> users = userMapper.selectList(queryWrap);
users.forEach(s -> System.out.println(s));
return "请求成功:"+ users;
}
}
查询返回结果:
添加用户
注意:因为我使用的是Sqlserver数据库,设置主键id为自增时是不能显示插入id值的,正规插入新建查询语句如下:
sql
set IDENTITY_INSERT t_user ON --打开显示插入
INSERT INTO t_user(id, uname, pwd, birthday) VALUES(6, 'Mingwan' , '1234567', '2002-11-11')
set IDENTITY_INSERT t_user OFF --关闭显示插入
而在springboot的MybatisPlus注解开发中如果在对应的类中添加id变量,直接在控制器中调用自动生成查询或插入等sql的方法,会涉及到类中所有成员变量,那么无论如何是会出现不能显示插入的错误。
解决办法:
- 在定义实体类时定义除了主键以外的成员变量,在控制器中调用自动生成查询或插入等sql的方法时就不会涉及到主键id,主键id的自增由Sqlserver数据库自己完成。
- 使用Mybatis注解开发,手动写sql语句可以只查询或插入部分字段,只需要保证查询或插入的字段与类中成员变量一一对应即可。
java
@Mapper
public interface UserMapper extends BaseMapper<User> {
//注意一定要在继承的BaseMapper泛型上写上要映射的类;
//另外,在MybatisPlus注解开发中,
//因为可以直接在控制器中调用自动生成查询或插入等sql的方法,会涉及到类中所有成员变量
//所以类中的成员变量一定要与数据库表字段一一对应。
}
java
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/getUser")
public String getUser(){
List<User> users = userMapper.selectList(null);
users.forEach(s -> System.out.println(s));
return "请求成功:"+ users;
}
@PostMapping("/insertUser")
public String insertUser(User user) {
int i = userMapper.insert(user);
if (i > 0) {
return "插入成功";
} else {
return "插入失败";
}
}
}
插入结果:
7 Mybatis多表查询和分页查询
7.1 查询用户并返回用户所有订单
由于涉及多表查询,需要在查询表的类中定义了非字段的属性,MybatisPlus自动生成sql的方法查询不到值,不适合用多表查询。需要通过Mybatis手动配置相关的注解和写sql语句来完成。
MybatisPlus可以使用Mybatis提供的@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置。
注解 | 说明 |
---|---|
@Results | 代替标签,表示查询的结果集。该注解中可以加入单个或多个@Result注解 |
@Result | 代替标签,@Result中可以使用以下属性: column:数据表的字段名称 property:类中对应的属性名 one:与@One注解配合,进行一对一的映射 many:与@Many注解配合,进行一对多的映射 |
@One | 代替标签,用于指定查询中返回的单一对象 通过select属性指定用于多表查询的方法 使用格式:@Result(column="xx", property="xx", one=@One(select="xx")) |
@Many | 代替标签,用于指定查询中返回的集合对象 使用格式:@Result(column="xx", property="xx", many=@Many(select="xx")) |
需求分析
在数据库中建立如下两张表:
查询用户的同时,查询出用户的订单情况,所以在建表时需要有让两张表产生关联的标识,那t_order表中uid字段就是用来描述订单对应的用户,当查询返回该用户信息时可以通过对应的uid查询返回所有订单。
代码编写和逻辑分析
所以编写多表查询代码时在原用户类的基础上增加一个订单属性orders,查询返回该用户信息时也能返回所有对应的订单信息。增加的这个属性在用户表里是不存在对应字段的,所以要通过对应的uid查询返回所有订单。
java
public class User {
//主键建议用Integer
@TableId(type=IdType.AUTO)
private Integer id;
private String uname;
private String pwd;
private String birthday;
//1.描述该用户所以订单
//2.还是那个问题,避免当要使用MybatisPlus提供的方法时,自动生成sql的方法,将其映射为数据库表字段。
private List<Order> orders;
Setter and Getter;
toString(){...};
}
因为在用户类中定义了非字段的属性orders,MybatisPlus自动生成sql的方法查询不到值。所以MybatisPlus对于多表查询是无能为力的,要使用Mybatis自定义查询方法。在用户类接口方法中使用Mybatis提供的@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置:
java
@Mapper
public interface UserMapper extends BaseMapper<User> {
@Select("select * from t_user")
@Results(
{
@Result(column = "id", property = "id"),
@Result(column = "uname", property = "uname"),
@Result(column = "pwd", property = "pwd"),
@Result(column = "birthday", property = "birthday"),
// 将id作为参数传递给selectOrders方法,然后该方法通过uid=#{id}查询所有的用户订单
@Result(column = "id", property = "orders", javaType = List.class,
many = @Many(select = "com.bree.mapper.OrderMapper.selectOrders"))
}
)
List<User> selectAllUsersAndOrder();
}
在订单类接口方法中定义通过uid查询的方法selectOrders():
java
@Mapper
public interface OrderMapper {
@Select("select * from t_order where uid = #{uid}")
List<Order> selectOrders(int uid);
}
在UserController中调用查询方法,并将返回的结果打印和响应:
java
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/selectAllUsersAndOrder")
public String selectAllUsersAndorder(){
List<User> users = userMapper.selectAllUsersAndOrder();
users.forEach(s-> System.out.println(s+"\r\n"));
return "请求成功:"+users;
}
}
多表查询返回结果:
7.2 查询订单并返回其对应的用户
需求分析
查询出订单的同时,查询出该订单对应的用户,t_order表中uid字段是让两张表产生关联的标识,就是用来描述订单对应的用户,当查询返回该订单信息时可以通过对应的uid查询返回订单对应的用户。
代码编写和逻辑分析
在原订单类的基础上增加一个用户属性users,查询返回该订单信息时也能返回其对应的用户信息。增加的这个属性在订单表里是不存在对应字段的,所以要通过对应的uid查询返回订单对应的用户。
java
public class Order {
@TableId(type=IdType.AUTO)
private Integer id;
private String total ;
private String uid;
@TableField("order_time")
private String ordertime;
//1.描述该订单对应的用户
//2.避免当要使用MybatisPlus提供的方法时,自动生成sql的方法,将其映射为数据库表字段。
private List<User> users;
Setter and Getter;
toString(){...};
}
同样的,在订单类接口方法中使用Mybatis提供的@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置:
java
@Mapper
public interface OrderMapper {
@Select("select * from t_order")
@Results(
{
@Result(column = "id", property = "id"),
@Result(column = "total", property = "total"),
@Result(column = "uid", property = "uid"),
@Result(column = "ordertime", property = "ordertime"),
// 将uid作为参数传递给queryUser方法,然后该方法通过id=#{uid}查询订单对应的用户
@Result(column = "uid", property = "users", javaType = List.class,
many = @Many(select = "com.bree.mapper.UserMapper.queryUser"))
}
)
List<Order> selectAllOrdersAndUser();
}
在OrderController中调用查询方法,并将返回的结果打印和响应:
java
@RestController
public class OrderController {
@Autowired
OrderMapper orderMapper;
@GetMapping("/selectAllOrdersAndUser")
public String selectAllOrdersAndUser(){
List<Order> orders = orderMapper.selectAllOrdersAndUser();
orders.forEach(System.out::println);
return "请求成功";
}
}
多表查询结果,如下结果示例是查询到的五条订单中的两条:
7.3 分页查询
分页查询类似于条件查询,进行分页查询只需调用分页查询方法时要传入分页规则对象page和唯一字段排序条件wrapper,不过在这之前需要在配置类中定义一个MybatisPlusInterceptor的分页拦截器,当我们进行Sql查询时都会进入这个拦截器。我使用的是SQLserver,所以定义为对Sqlserver数据库进行的分页查询。
java
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor Interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.SQL_SERVER);
Interceptor.addInnerInterceptor(paginationInnerInterceptor);
return Interceptor;
}
}
完成拦截器定义和配置后就可以调用分页查询的方法,传入分页规则对象page和唯一字段排序条件wrapper:
java
@RestController
public class OrderController {
@Autowired
OrderMapper orderMapper;
//分页查询
@GetMapping("/order/findByPage")
public IPage findByPage(){
//设置分页规则,分页起始值和每页条数
Page<Order> page = new Page<>(0,3);
//Sqlserver中需要加一个唯一字段排序,否则系统排序结果不唯一,报
QueryWrapper<Order> wrapper = new QueryWrapper();
wrapper.orderByDesc("id");
//接收分页结果集
IPage iPage = orderMapper.selectPage(page,wrapper);
return iPage;
}
}
查询返回结果: