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 来指定方法请求方式
问题:我们表现层增删改方法返回true或者false表示是否成功,getById()方法返回一个json对象,getAll()方法返回一个json对象数组,这里就出现了三种格式的响应结果,极其不利于前端解析。
解决:我们需要统一响应结果的格式
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
@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
类型:方法注解
位置:专用于异常处理的控制器方法上方
作用:设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原始控制器执行,并转入当前方法执行
说明:此类方法可以根据处理的异常不同,制作多个方法分别处理对应的异常
项目当前异常的分类以及对应类型异常该如何处理?
业务异常(BusinessException)
规范的用户行为产生的异常
不规范的用户行为操作产生的异常
系统异常(SystemException)
其他异常(Exception)
业务异常(BusinessException)
系统异常(SystemException)
发送特定消息给运维人员,提醒维护
其他异常(Exception)
发送固定消息传递给用户,安抚用户
发送特定消息给编程人员,提醒维护(纳入预期范围内)
记录日志
根据异常分类自定义异常类
自定义项目系统级异常
//自定义异常处理器,用于封装异常信息,对异常进行分类
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整合流程
创建数据库,创建Maven工程【javaweb】,添加依赖
添加页面
SSM整合
Spring
MyBatis
SpringMVC
springmvc.xml
web.xml
功能模块
表与实体类
工具类(Result、Code)
dao(接口+自动代理)
service(接口+实现类)
controller
SSM整合配置
创建工程,添加依赖和插件
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.1.2.RELEASEversion>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.4version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.23version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.6version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.6version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.1.2.RELEASEversion>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.20version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.3version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
<version>1.2.3version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.9.6version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.18version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.mavengroupId>
<artifactId>tomcat7-maven-pluginartifactId>
<version>2.2version>
<configuration>
<port>80port>
<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
<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">
<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>
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="com.execise.bean"/>
bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.execise.dao"/>
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
beans>
Spring整合SpringMVC
定义springmvc.xml
<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">
<context:component-scan base-package="com.execise"/>
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
bean>
<mvc:default-servlet-handler/>
<import resource="spring-mybatis.xml"/>
beans>
web.xml
<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">
<servlet>
<servlet-name>dispatcherservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>dispatcherservlet-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);
}