文章目录
一、RestFul
REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的。Fielding是一个非常重要的人,他是HTTP协议(1.0版和1.1版)的主要设计者、Apache服务器软件的作者之一、Apache基金会的第一任主席。所以,他的这篇论文一经发表,就引起了关注,并且立即对互联网开发产生了深远的影响。
他这样介绍论文的写作目的:
“本文研究计算机科学两大前沿----软件和网络----的交叉点。长期以来,软件研究主要关注软件设计的分类、设计方法的演化,很少客观地评估不同的设计选择对系统行为的影响。而相反地,网络研究主要关注系统之间通信行为的细节、如何改进特定通信机制的表现,常常忽视了一个事实,那就是改变应用程序的互动风格比改变互动协议,对整体表现有更大的影响。我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。”
RESTful 是一种设计风格。它不是一种标准,也不是一种软件,而是一种思想。
特点:
每一个URI(请求地址)代表1种资源;
-
以前我们认为url地址它是一个动作: 增删改查的动作
-
localhost:8080/项目名/findAllUser
-
lolcahost:8080/项目名/deleteUser?id=3
-
-
rest设计风格认为地址是一种资源,体现的只有名词,而没有动词。
-
localhost:8080/项目名/user/3 : 删除id为3
-
localhost:8080/项目名/user/3 : 查询id为3
-
客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源;、
-
由于地址不能体现出来动作,包含的都是名词,没有动词,那么服务端如何区分出来客户端想要执行的是什么操作呢?
-
采用请求方式来区分 localhost:8080/项目名/user/3
-
新增 ----- post请求
-
查询 ----- get请求
-
删除 ----- delete请求
-
更新 ----- put请求
-
客户端与服务端之间的交互在请求之间是无状态的,从客户端到服务端的每个请求都必须包含理解请求所必需的信息
接口结构
如何设计接口
域名
应该尽量将API部署在专用域名之下。 第三方SDK来说,比较有用。
http://api.example.com 或者 http://www.example.com/api/
版本
将API的版本号放在url中:http://www.example.com/api/v1.0
路径
在RESTful架构中,每个地址代表一种资源(resource),所以地址中不能有动词,只能有名词,而且所用的名词往往与数据库的表名对应。
具体操作
对于资源的具体操作类型,由HTTP动词表示。常用的HTTP动词有下面四个(括号里是对应的SQL命令)
GET(SELECT):从服务器取出资源(一项或多项)。
POST(CREATE):在服务器新建一个资源。
PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
DELETE(DELETE):从服务器删除资源。
还有三个不常用的HTTP动词。
PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
HEAD:获取资源的元数据。
OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的
示例说明
GET /user:列出所有用户
POST /user:新建一个用户
GET /user/{id}:获取某个指定用户的信息
PUT /user:更新某个指定用户的信息(提供该用户的全部信息)
DELETE /user/{id}:删除某个用户
-
原来的方式
http://127.0.0.1/user/find?id=3 GET方法,根据用户id获取数据
http://127.0.0.1/user/update POST方法,用户修改
http://127.0.0.1/user/add POST方法,用户新增
http://127.0.0.1/user/deleteUser?id=3 GET/POST方法,用户根据id删除 -
RestFul方式
http://127.0.0.1/user/{id} GET方法,根据用户id获取数据
http://127.0.0.1/user/{id} DELETE方法,用户根据id删除http://127.0.0.1/user/ GET 方法 查询所有的用户
http://127.0.0.1/user/ PUT方法,用户修改
http://127.0.0.1/user/ POST方法,用户新增
小结
-
RESTful 是一种设计风格 , 可以用,也可以不用!
-
每一个URI代表1种资源,地址里面只能出现名词,不能出现动词。
-
客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源;
基本实现
在postman工具里面测试
User
package com.execise.bean;
import lombok.Data;
@Data
public class User {
private String username;
private String password;
}
UserController
package com.execise.controller;
import com.execise.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
/*
这是用来处理一切与用户有关请求的controller
*/
@Controller
public class UserController {
/*
新增:
以前: localhost:82/addUser GET|POST
restFul : localhost:82/user POST
*/
// @RequestMapping(value = "/user", method = RequestMethod.POST)
@ResponseBody
@PostMapping("/user")
public String add(User user ){
System.out.println("add..." + user);
return "add success...";
}
/*
删除:
以前: localhost:82/deleteUser?id=1 GET
restFul: localhost:82/user/1 DELETE
*/
@ResponseBody
@DeleteMapping("/user/{id}")
public String delete(@PathVariable int id){
System.out.println("delete...id=" + id);
return "delete success...";
}
/*
修改:
以前: localhost:82/updateUser GET|POST
restFul: localhost:82/user PUT
更新的操作比较特殊一些:
springmvc不会从put请求里面拿请求体的数据出来,赋值给方法参数。
所以看到的都是null!
*/
@ResponseBody
@PutMapping("/user")
public String update(User user){
System.out.println("update..." + user);
return "update success...";
}
/*
根据id来查询用户:
以前: localhost:82/findUserById?id=1 GET
restFul: localhost:82/user/1 GET
*/
@ResponseBody
@GetMapping("/user/{id}")
public String findById(@PathVariable int id){
System.out.println("findById..." + id);
return "findById success...";
}
/*
查询所有:
以前: localhost:82/findAll GET
restFul: localhost:82/user GET
*/
@ResponseBody
@GetMapping("/user")
public String findAll(){
System.out.println("findAll..." );
return "findAll success...";
}
}
小结
-
创建Maven web工程
-
创建Pojo
-
创建Controller ,定义增删改查方法
-
分别使用 get | post | put | delete 来指定方法请求方式
二、表现层数据封装
1 表现层响应数据的问题
问题:我们表现层增删改方法返回true或者false表示是否成功,getById()方法返回一个json对象,getAll()方法返回一个json对象数组,这里就出现了三种格式的响应结果,极其不利于前端解析。
解决:我们需要统一响应结果的格式
2 定义Result类封装响应结果
Result类封装响应结果
public class Result {
//描述统一格式中的数据
private Object data;
//描述统一格式中的编码,用于区分操作,可以简化配置0或1表示成功失败
private Integer code;
//描述统一格式中的消息,可选属性
private String msg;
public Result() {
}
public Result(Integer code,Object data) {
this.data = data;
this.code = code;
}
public Result(Integer code, Object data, String msg) {
this.data = data;
this.code = code;
this.msg = msg;
}
//同学们自己添加getter、setter、toString()方法
}
注意事项:
Result类中的字段并不是固定的,可以根据需要自行增减
Code类封装响应码
//状态码
public class Code {
public static final Integer SAVE_OK = 20011;
public static final Integer DELETE_OK = 20021;
public static final Integer UPDATE_OK = 20031;
public static final Integer GET_OK = 20041;
public static final Integer SAVE_ERR = 20010;
public static final Integer DELETE_ERR = 20020;
public static final Integer UPDATE_ERR = 20030;
public static final Integer GET_ERR = 20040;
}
注意事项:
Code类的常量设计也不是固定的,可以根据需要自行增减,例如将查询再进行细分为GET_OK,GET_ALL_OK,GET_PAGE_OK
3 表现层数据封装返回Result对象
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookService bookService;
@PostMapping
public Result save(@RequestBody Book book) {
boolean flag = bookService.save(book);
return new Result(flag ? Code.SAVE_OK:Code.SAVE_ERR,flag);
}
@PutMapping
public Result update(@RequestBody Book book) {
boolean flag = bookService.update(book);
return new Result(flag ? Code.UPDATE_OK:Code.UPDATE_ERR,flag);
}
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id) {
boolean flag = bookService.delete(id);
return new Result(flag ? Code.DELETE_OK:Code.DELETE_ERR,flag);
}
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id) {
Book book = bookService.getById(id);
Integer code = book != null ? Code.GET_OK : Code.GET_ERR;
String msg = book != null ? "" : "数据查询失败,请重试!";
return new Result(code,book,msg);
}
@GetMapping
public Result getAll() {
List<Book> bookList = bookService.getAll();
Integer code = bookList != null ? Code.GET_OK : Code.GET_ERR;
String msg = bookList != null ? "" : "数据查询失败,请重试!";
return new Result(code,bookList,msg);
}
}
三、异常处理器
程序开发过程中不可避免的会遇到异常现象,我们不能让用户看到这样的页面数据
出现异常现象的常见位置与常见诱因如下:
-
框架内部抛出的异常:因使用不合规导致
-
数据层抛出的异常:因外部服务器故障导致(例如:服务器访问超时)
-
业务层抛出的异常:因业务逻辑书写错误导致(例如:遍历业务书写操作,导致索引异常等)
-
表现层抛出的异常:因数据收集、校验等规则导致(例如:不匹配的数据类型间导致异常)
-
工具类抛出的异常:因工具类书写不严谨不够健壮导致(例如:必要释放的连接长期未释放等)
编写异常处理器
@RestControllerAdvice //用于标识当前类为REST风格对应的异常处理器
public class ProjectExceptionAdvice {
//统一处理所有的Exception异常
@ExceptionHandler(Exception.class)
public Result doOtherException(Exception ex){
return new Result(666,null);
}
}
使用异常处理器之后的效果
@RestControllerAdvice注解介绍
-
名称:@RestControllerAdvice
-
类型:类注解
-
位置:Rest风格开发的控制器增强类定义上方
-
作用:为Rest风格开发的控制器类做增强
-
说明:此注解自带@ResponseBody注解与@Component注解,具备对应的功能
@ExceptionHandler注解介绍
-
名称:@ExceptionHandler
-
类型:方法注解
-
位置:专用于异常处理的控制器方法上方
-
作用:设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原始控制器执行,并转入当前方法执行
-
说明:此类方法可以根据处理的异常不同,制作多个方法分别处理对应的异常
项目异常处理方案
项目当前异常的分类以及对应类型异常该如何处理?
1 项目异常分类
业务异常(BusinessException)
-
规范的用户行为产生的异常
-
不规范的用户行为操作产生的异常
系统异常(SystemException)
- 项目运行过程中可预计且无法避免的异常
其他异常(Exception)
- 编程人员未预期到的异常
2 项目异常处理方案
业务异常(BusinessException)
- 发送对应消息传递给用户,提醒规范操作
系统异常(SystemException)
- 发送固定消息传递给用户,安抚用户
发送特定消息给运维人员,提醒维护
- 记录日志
其他异常(Exception)
-
发送固定消息传递给用户,安抚用户
-
发送特定消息给编程人员,提醒维护(纳入预期范围内)
-
记录日志
3 项目异常处理代码实现
根据异常分类自定义异常类
自定义项目系统级异常
//自定义异常处理器,用于封装异常信息,对异常进行分类
public class SystemException extends RuntimeException{
private Integer code;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public SystemException(Integer code, String message) {
super(message);
this.code = code;
}
public SystemException(Integer code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
}
自定义项目业务级异常
//自定义异常处理器,用于封装异常信息,对异常进行分类
public class BusinessException extends RuntimeException{
private Integer code;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public BusinessException(Integer code, String message) {
super(message);
this.code = code;
}
public BusinessException(Integer code,String message,Throwable cause) {
super(message, cause);
this.code = code;
}
}
自定义异常编码(持续补充)
public class Code {
//之前其他状态码省略没写,以下是新补充的状态码,可以根据需要自己补充
public static final Integer SYSTEM_ERR = 50001;
public static final Integer SYSTEM_TIMEOUT_ERR = 50002;
public static final Integer SYSTEM_UNKNOW_ERR = 59999;
public static final Integer BUSINESS_ERR = 60002;
}
触发自定义异常
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
//在getById演示触发异常,其他方法省略没有写进来
public Book getById(Integer id) {
//模拟业务异常,包装成自定义异常
if(id <0){
throw new BusinessException(Code.BUSINESS_ERR,"请不要使用你的技术挑战我的耐性!");
}
}
}
在异常通知类中拦截并处理异常
@RestControllerAdvice //用于标识当前类为REST风格对应的异常处理器
public class ProjectExceptionAdvice {
//@ExceptionHandler用于设置当前处理器类对应的异常类型
@ExceptionHandler(SystemException.class)
public Result doSystemException(SystemException ex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
return new Result(ex.getCode(),null,ex.getMessage());
}
@ExceptionHandler(BusinessException.class)
public Result doBusinessException(BusinessException ex){
return new Result(ex.getCode(),null,ex.getMessage());
}
//除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常
@ExceptionHandler(Exception.class)
public Result doOtherException(Exception ex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试!");
}
}
测试:在postman中发送请求访问getById方法,传递参数-1,得到以下结果:
四、拦截器
问题1:拦截器拦截的对象是谁?
问题2:拦截器和过滤器有什么区别?
拦截器概念和作用
拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行
作用:
-
在指定的方法调用前后执行预先设定的代码
-
阻止原始方法的执行
-
总结:增强
核心原理:AOP思想
拦截器和过滤器的区别
归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强
拦截器代码实现
【第一步】定义拦截器
做法:定义一个类,实现HandlerInterceptor接口即可
@Component //注意当前类必须受Spring容器控制
//定义拦截器类,实现HandlerInterceptor接口
public class ProjectInterceptor implements HandlerInterceptor {
@Override
//原始方法调用前执行的内容
//返回值类型可以拦截控制的执行,true放行,false终止
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle..."+contentType);
return true;
}
@Override
//原始方法调用后执行的内容
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}
@Override
//原始方法调用完成后执行的内容
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}
【第二步】配置加载拦截器
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Autowired
private ProjectInterceptor projectInterceptor;
@Override
protected void addInterceptors(InterceptorRegistry registry) {
//配置拦截器
registry.addInterceptor(projectInterceptor)
.addPathPatterns("/books","/books/*");
}
}
使用标准接口WebMvcConfigurer简化开发(注意:侵入式较强)
@Configuration
@ComponentScan({"com.execise.controller"})
@EnableWebMvc
//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
public class SpringMvcConfig implements WebMvcConfigurer {
@Autowired
private ProjectInterceptor projectInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//配置多拦截器
registry.addInterceptor(projectInterceptor)
.addPathPatterns("/books","/books/*");
}
}
拦截器流程分析
拦截器参数
postHandle()和afterCompletion()方法都是处理器方法执行之后执行,有什么区别?
前置处理
//原始方法调用前执行的内容
//返回值类型可以拦截控制的执行,true放行,false终止
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle..."+contentType);
return true;
}
参数
-
request:请求对象
-
response:响应对象
-
handler:被调用的处理器对象,本质上是一个方法对象,对反射技术中的Method对象进行了再包装
返回值为false,被拦截的处理器将不执行。
后置处理
//原始方法调用后执行的内容
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
}
参数
modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行跳转
注意:如果处理器方法出现异常了,该方法不会执行
完成后处理
//原始方法调用完成后执行的内容
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
参数
ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理
注意:无论处理器方法内部是否出现异常,该方法都会执行。
拦截器链配置
什么是拦截器链?
多个拦截器配置
定义第二个拦截器
@Component
public class ProjectInterceptor2 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle...222");
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...222");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...222");
}
}
配置第二个拦截器
@Configuration
@ComponentScan({"com.execise.controller"})
@EnableWebMvc
//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
public class SpringMvcConfig implements WebMvcConfigurer {
@Autowired
private ProjectInterceptor projectInterceptor;
@Autowired
private ProjectInterceptor2 projectInterceptor2;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//配置多拦截器
registry.addInterceptor(projectInterceptor)
.addPathPatterns("/books","/books/*");
registry.addInterceptor(projectInterceptor2)
.addPathPatterns("/books","/books/*");
}
}
多个连接器工作流程分析
-
当配置多个拦截器时,形成拦截器链
-
拦截器链的运行顺序参照拦截器添加顺序为准
-
当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
-
当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作
五、整合SSM
SSM整合流程
-
创建数据库,创建Maven工程【javaweb】,添加依赖
-
添加页面
-
SSM整合
-
Spring
- applicationContext.xml
-
MyBatis
- db.properties
-
SpringMVC
-
springmvc.xml
-
web.xml
-
-
-
功能模块
-
表与实体类
-
工具类(Result、Code)
-
dao(接口+自动代理)
-
service(接口+实现类)
- 业务层接口测试(整合JUnit)
-
controller
- 表现层接口测试(PostMan)
-
SSM整合配置
创建工程,添加依赖和插件
<!-- 设置JDK编译版本1.8 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<!--依赖管理-->
<dependencies>
<!--junit单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--Spring+SpringMVC核心依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.2.RELEASE</version>
</dependency>
<!--AOP-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<!--整合Mybatis-->
<!--1. 数据库依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--2. 连接池依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.23</version>
</dependency>
<!--3. mybatis本身的依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!--4. 整合mybatis和spring的依赖-->
<!--MyBatis提供的和Spring进行整合的jar包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!--spring对jdbc封装的jar包也要导入进来,否则mybatis无法整合-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.2.RELEASE</version>
</dependency>
<!--5. 日志依赖-->
<!-- 添加slf4j日志api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.20</version>
</dependency>
<!-- 添加logback-classic依赖 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- 添加logback-core依赖 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<!--jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
<!--Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.18</version>
<scope>provided</scope>
</dependency>
<!--Servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- 指定端口 -->
<port>80</port>
<!-- 请求路径 -->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
Spring整合Mybatis
创建数据库和表
-- 创建ssm_db数据库
CREATE DATABASE IF NOT EXISTS day35_ssm CHARACTER SET utf8;
-- 使用ssm_db数据库
USE day35_ssm;
-- 创建tbl_book表
CREATE TABLE tbl_book(
id INT PRIMARY KEY AUTO_INCREMENT, -- 图书编号
`type` VARCHAR(100), -- 图书类型
`name` VARCHAR(100), -- 图书名称
description VARCHAR(100) -- 图书描述
);
-- 添加初始化数据
INSERT INTO tbl_book VALUES(NULL,'计算机理论','Spring实战 第5版','Spring入门经典教材,深入理解Spring原理技术内幕');
INSERT INTO tbl_book VALUES(NULL,'计算机理论','Spring 5核心原理与30个类手写实战','十年沉淀之作,手写Spring精华思想');
INSERT INTO tbl_book VALUES(NULL,'计算机理论','Spring 5设计模式','深入Spring源码剖析,Spring源码蕴含的10大设计模式');
INSERT INTO tbl_book VALUES(NULL,'市场营销','直播就该这么做:主播高效沟通实战指南','李子柒、李佳琦、薇娅成长为网红的秘密都在书中');
INSERT INTO tbl_book VALUES(NULL,'市场营销','直播销讲实战一本通','和秋叶一起学系列网络营销书籍');
INSERT INTO tbl_book VALUES(NULL,'市场营销','直播带货:淘宝、天猫直播从新手到高手','一本教你如何玩转直播的书,10堂课轻松实现带货月入3W+');
db.properties属性文件
db.driverClass=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/day35_ssm
db.username=root
db.password=root
Spring整合MyBatis
定义 spring-mybatis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--0. 扫描包-->
<!-- <context:component-scan base-package="com.execise"/>-->
<!--整合Spring和mybatis-->
<!--1. 数据库连接池-->
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${db.driverClass}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</bean>
<!--2. SqlSessionFactoryBean-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="com.execise.bean"/>
</bean>
<!--3. MapperScannerConfigurer-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.execise.dao"/>
</bean>
<!--4. 事务的配置-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--5. 打开事务的注解开关 :: @Transactional-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
Spring整合SpringMVC
定义springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--1. 扫描包-->
<context:component-scan base-package="com.execise"/>
<!--2. 注解驱动-->
<mvc:annotation-driven/>
<!--3. 视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--4. 静态资源处理-->
<mvc:default-servlet-handler/>
<!--5. 导入spring和mybatis整合的配置文件-->
<import resource="spring-mybatis.xml"/>
</beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!--配置前端控制器 DispatcherServlet-->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
功能模块开发
查询所有
页面
//添加
handleAdd() {
//1. 提交请求
axios.post("/books", this.formData).then(response=>{
console.log("添加的结果:");
console.log(response);
//2. 判定
this.dialogFormVisible = false;
if(response.data.code === 20001){
//提示
this.$message.success(response.data.msg);
//添加成功了,需要重新载入数据
this.getAll();
}else{
this.$message.error(response.data.msg);
}
})
},
controller
package com.execise.controller;
/*
所有关于书籍的增删改查的操作,都交给这个类处理
*/
import com.execise.bean.Book;
import com.execise.bean.Result;
import com.execise.constant.Code;
import com.execise.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RequestMapping("/books")
@RestController
public class BookController {
@Autowired
private BookService bs;
/*
查询所有
*/
@GetMapping
public Result findAll(){
Result result = null;
try {
//1. 调用service
List<Book> list = bs.findAll();
//成功
result = new Result(Code.GET_ALL_BOOK_SUCCESS, list , "查询所有书籍成功");
} catch (Exception e) {
e.printStackTrace();
//失败
result = new Result(Code.GET_ALL_BOOK_FAILED, "查询所有书籍失败");
}
return result;
}
}
service
package com.execise.service;
import com.execise.bean.Book;
import java.util.List;
public interface BookService {
List<Book> findAll();
}
package com.execise.service.impl;
import com.execise.bean.Book;
import com.execise.dao.BookDao;
import com.execise.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
public class BookServiceImpl implements BookService {
@Autowired
private BookDao dao;
@Override
public List<Book> findAll() {
return dao.findAll();
}
}
dao
package com.execise.dao;
import com.execise.bean.Book;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
public interface BookDao {
@Select("select * from tbl_book")
List<Book> findAll();
}
添加图书
页面
//添加
handleAdd() {
//1. 提交请求
axios.post("/books", this.formData).then(response=>{
console.log("添加的结果:");
console.log(response);
//2. 判定
this.dialogFormVisible = false;
if(response.data.code === 20001){
//提示
this.$message.success(response.data.msg);
//添加成功了,需要重新载入数据
this.getAll();
}else{
this.$message.error(response.data.msg);
}
})
},
controller
@RequestMapping("/books")
@RestController
public class BookController {
@PostMapping
public Result add(@RequestBody Book book){
//1. 调用service干活
int row = bs.add(book);
//2. 响应
Result result = null;
if(row > 0 ){
result = new Result(Code.ADD_SUCCESS , "添加书籍成功!");
}else{
result = new Result(Code.ADD_FAILED , "添加书籍失败!");
}
return result;
}
}
service
package com.execise.service;
import com.execise.bean.Book;
import java.util.List;
public interface BookService {
int add(Book book);
}
package com.execise.service.impl;
import com.execise.bean.Book;
import com.execise.dao.BookDao;
import com.execise.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
public class BookServiceImpl implements BookService {
@Autowired
private BookDao dao;
@Override
public int add(Book book) {
return dao.add(book);
}
dao
package com.execise.dao;
import com.execise.bean.Book;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
public interface BookDao {
@Insert("insert into tbl_book values (null ,#{type}, #{name} , #{description} )")
int add(Book book);
}
更新图书
页面
//弹出编辑窗口
handleUpdate(row) {
//1. 弹出编辑的对话框
this.dialogFormVisible4Edit = true;
//2. 回显数据
//this.formData = row;
this.formData = JSON.parse(JSON.stringify(row));
},
//编辑
handleEdit() {
//1. 发起请求
axios.put("/books" , this.formData).then(response=>{
console.log("更新结果:");
console.log(response);
//不管成功或者失败,都要让对话框消失
this.dialogFormVisible4Edit = false;
if(response.data.code === 20002){
this.$message.success(response.data.msg);
//重新载入数据
this.getAll();
}else{
this.$message.error(response.data.msg);
}
});
},
controller
package com.execise.controller;
/*
所有关于书籍的增删改查的操作,都交给这个类处理
*/
import com.execise.bean.Book;
import com.execise.bean.Result;
import com.execise.constant.Code;
import com.execise.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RequestMapping("/books")
@RestController
public class BookController {
@PutMapping
public Result update(@RequestBody Book book){
System.out.println("book = " + book);
//1. 交代service干活
int row = bs.update(book);
//2. 响应
Result result = null;
if(row > 0){
result = new Result(Code.UPDATE_SUCCESS , "更新图书成功" );
}else{
result = new Result(Code.UPDATE_FAILED , "更新图书失败" );
}
return result;
}
}
service
package com.execise.service;
import com.execise.bean.Book;
import java.util.List;
public interface BookService {
int update(Book book);
}
@Service
@Transactional
public class BookServiceImpl implements BookService {
@Override
public int update(Book book) {
return dao.update(book);
}
}
dao
package com.execise.dao;
import com.execise.bean.Book;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
public interface BookDao {
@Update("update tbl_book set type=#{type} , name=#{name} , description=#{description} where id = #{id}")
int update(Book book);
}
删除图书
页面
// 删除
handleDelete(row) {
this.$confirm('确定删除该图书吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
//点击确定就来到这里了。
//axios.get("请求地址?id="+row.id)
axios.delete("/books/"+row.id).then(response=>{
console.log("删除结果:");
console.log(response);
if(response.data.code === 20003){
this.$message.success(response.data.msg);
this.getAll();
}else{
this.$message.error(response.data.msg);
}
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
}
controller
package com.execise.controller;
/*
所有关于书籍的增删改查的操作,都交给这个类处理
*/
import com.execise.bean.Book;
import com.execise.bean.Result;
import com.execise.constant.Code;
import com.execise.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RequestMapping("/books")
@RestController
public class BookController {
@DeleteMapping("/{id}")
public Result delete(@PathVariable int id){
//1. 调用service
int row = bs.delete(id);
//2. 响应
Result result = null;
if(row > 0){
result = new Result(Code.DELETE_SUCCESS , "删除图书成功" );
}else{
result = new Result(Code.DELETE_FAILED , "删除图书失败" );
}
return result;
}
}
service
package com.execise.service;
import com.execise.bean.Book;
import java.util.List;
public interface BookService {
int delete(int id );
}
@Service
@Transactional
public class BookServiceImpl implements BookService {
@Override
public int delete(int id) {
return dao.delete(id);
}
}
dao
package com.execise.dao;
import com.execise.bean.Book;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
public interface BookDao {
@Delete("delete from tbl_book where id = #{id}")
int delete(int id);
}