SpringMVC
1、springMVC简介:
SpringMVC概述:
- springMVC技术与Service技术功能等同,均属于web层开发技术
-
SpringMVC是一种基于Java实现MVC模型的轻量级web框架
-
优点
- 使用简单,开发便捷(相比于Servlet)
-
springMVC原始开发的工作流程
2、springMVC入门案例
2.1、操作步骤:
- 使用springMVC技术需要导入springMVC坐标于servlet坐标和tomcat插件
<!--1、导入springMVC和servlet的坐标-->
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 配置Tomcat插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<!--端口号-->
<port>8088</port>
<!--设置项目路径-->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
- 创建springMVC控制器类(等同于servlet功能)
/**
* @author: anle
* @date: 2023/04/12 11:07
*
* 2、定义Controller类
* 2.1使用@Controller来定义bean
**/
@Controller
public class UserController {
//2.2 设置当前操作的访问路径
@RequestMapping("/sho")
//2.3 设置当前操作的返回值类型
@ResponseBody
public String sho(){
System.out.println("user...sho");
return "{'module':'springmvc'}";
}
}
-
初始化springMVC环境(同spring环境),设置springMVC加载对应的bean
/** * @author: anle * @date: 2023/04/12 11:15 **/ //3、创建springmvc的配置文件,加载controller对应的bean @Configuration @ComponentScan("com.anle.controller") public class SpringMvcConfig { }
-
初始化servlet容器,加载springMVC环境并设置springMVC技术处理的请求
/**
* @author: anle
* @date: 2023/04/12 11:18
**/
//4、定义一个servlet容器的配置类,在里面加载spring的配置
public class ServletConfig extends AbstractDispatcherServletInitializer {
//加载springMvc容器配置
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
//设置那些请求归属sprigMVC处理
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
//加载spring配置
@Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
2.2、相关注解:
-
名称:@Controller
-
类型:类注解
-
位置:springMVC控制器类上方
-
作用:设定springMVC的核心控制器bean
-
范例:
@Controller public class UserController { }
-
名称:@RequestMapping
-
类型:类注解
-
位置:springMVC控制器类上方
-
作用:设置当前控制器方法请求访问的路径
-
范例:
//2.2 设置当前操作的访问路径 @RequestMapping("/sho") //2.3 设置当前操作的返回值类型 @ResponseBody public String sho(){ System.out.println("user...sho"); return "{'module':'springmvc'}"; }
-
相关属性:value(默认):请求访问路径
-
名称:@ResponseBody
-
类型:类注解
-
位置:springMVC控制器类上方
-
作用:设置当前控制器方法响应内容为当前返回值,无需解析
-
范例:
//2.2 设置当前操作的访问路径 @RequestMapping("/sho") //2.3 设置当前操作的返回值类型 @ResponseBody public String sho(){ System.out.println("user...sho"); return "{'module':'springmvc'}"; }
2.3、springMVC入门程序开发总结
- 一次性工作
- 创建工程,设置服务器,加载工程
- 导入坐标
- 创建web容器启动类,加载springMVC配置,并设置springMVC请求拦截路径
- springMVC核心配置类(设置配置类,扫描controller包,加载controller控制器包)
- 多次工作
- 定义处理请求控制器类
- 定义请求的控制方法,并配置映射路径(@RequestMapping)与返回值json数据(@ResponseBody)
2.4、servlet容器简介:
-
AbstractDispatcherServletInitializer类是springMVC提供的快速初始化web3.0容器的抽象类
-
AbstractDispatcherServletInitializer提供三个接口方提供用户使用
-
createServletApplicationContext()方法,创建servlet容器时,加载springMVC对应的bean并放入
WebApplicationContext对象范围中,而 WebApplicationContext的作用范围为ServletContext范围,即整个web容器
-
//加载springMvc容器配置
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
- getServletMappings()方法,设定springMVC对应的请求映射路径,设置为/表示拦截所有请求,任意请求都将转入到springMVC进行处理
//设置那些请求归属sprigMVC处理
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
- createRootApplicationContext()方法,如果创建servlet容器时需要加载非springMVC对应的bean,使用当前方法进行,使用方法式同createRootApplicationContext()
//加载spring配置
@Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
3、springMVC-bean加载控制
- springMVC相关bean(表现层bean)
- spring控制bean
- 业务层
- 功能bean(service)
- 功能bean(DataSource)
包结构:
问题:因为功能不同我们怎么去避免spring错误加载到springMVC的bean?
解决方法:加载spring控制的bean的时候排除掉springMVC控制的bean
- springMVC相关bean加载控制
- springMVC加载的bean对应在com.anle.controller包内
- spring相关bean加载控制
- 方式一:spring加载bean设定扫描范围为com.anle ,排除controller包类的bean
- 方式二:spring加载bean设置扫描范围精准范围,类如:service包 dao包等
- 方式三:不区分spring和springMVC的环境,加载到同一环境中
3.1、使用的相关注解
-
名称:@ComponentScan
-
类型:类注解
-
范例:
@ComponentScan(value = "com.anle", excludeFilters = @ComponentScan.Filter( type = FilterType.ANNOTATION, classes = Controller.class ) )
-
属性:
- excludeFilters:排除扫描路径中加载的bean,需要指定类别(type)与具体项(classes)
- includeFiltres:加载指定的bean,需要指定类别(type)与具体项(classes)
3.2bean的完整加载格式
/**
* @author: anle
* @date: 2023/04/12 11:18
**/
//4、定义一个servlet容器的配置类,在里面加载spring的配置
public class ServletConfig extends AbstractDispatcherServletInitializer {
//加载springMvc容器配置
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
//设置那些请求归属sprigMVC处理
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
//加载spring配置
@Override
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringConfig.class);
return ctx;
}
}
-
简化开发的格式:
public class ServletConfig2 extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } }
4、Apipost工具介绍
4.1、Apipost简介
-
官网:Apipost-API
-
Apipost = Postman + Swagger + Mock + Jmeter
后端、前端、测试,同时在线协作,内容实时同步
-
作用:常用于进行接口测试
-
特征:
- 简单
- 实用
- 美观
4.2、Apipsot使用教程
5、设置请求路径
- 团队多人开发,每个人设置不同的请求路径,冲突问题如何解决?
- 设置模块名作为请求路径前缀
/**
* @author: anle
* @date: 2023/04/18 08:37
**/
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/sho")
@ResponseBody
public String sho() {
System.out.println("user...sho");
return "{'module':'user sho}";
}
@RequestMapping("/delete")
@ResponseBody
public String delete() {
System.out.println("user...delete");
return "{'module':'user delete}";
}
}
5.1、请求映射路径
-
名称:@RequestMapping
-
类型:方法注解 类注解
-
位置:springMVC控制器方法定义上方
-
作用:设置当前控制器方法请求访问路径,如果设置在类上统一设置当前控制器方法请求访问当前前缀
-
范例:
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/sho") @ResponseBody public String sho() { System.out.println("user...sho"); return "{'module':'user sho}"; }
-
属性
- value(默认):请求访问路径,或者访问路径前缀。
6、get请求与post请求发送普通参数
6.1、Get请求参数
-
普通参数:url地址参数,地址参数与形参变量相同,定义形参即可接收参数
/**
* @author: anle
* @date: 2023/04/21 10:57
*
**/
@Controller
public class UserController {
//普通参数的传递
@RequestMapping("/common")
@ResponseBody
public String common(String name , String age){
System.out.println("普通的参数传递--->"+name);
System.out.println("普通的参数传递--->"+age);
return "{module: 'common'}";
}
}
6.2、Post请求
- 提交post请求的时候,在表单直接提交即可
/**
* @author: anle
* @date: 2023/04/21 10:57
*
**/
@Controller
public class UserController {
//普通参数的传递
@RequestMapping("/common")
@ResponseBody
public String common(String name , String age){
System.out.println("普通的参数传递--->"+name);
System.out.println("普通的参数传递--->"+age);
return "{module: 'common'}";
}
}
- 注意:在我们传递的参数是中文时可能会出现中文乱码的
6.3、解决中文乱码的方法:
-
get请求中文乱码
-
在自己下载的tomcat文件夹里面的conf文件中的server.xml文件里将原配置:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/>
-
修改为:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="utf-8"/>
-
-
post请求乱码
-
方法一:为web容器增加过滤器并指定字符集,spring-web包中提供了专用的字符集过滤
//解决乱码问题 @Override protected Filter[] getServletFilters() { CharacterEncodingFilter filter = new CharacterEncodingFilter(); filter.setEncoding("UTF-8"); return new Filter[]{filter}; }
-
方法二:
-
spring MVC中默认的编码格式为“ISO-8859-1”,因此造成乱码。
解决:
在web.xml中配置Spring字符过滤器<!--配置解决中文乱码的过滤器--> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!--配置过滤器初始化参数--> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
-
7、5中不同参数请求
7.1、普通参数
-
普通参数:ur地址传参,地址参数与形参变量名相同,定义形参即可接收参数
//普通参数,请求参数与形参不同
@RequestMapping("/ordinary")
@ResponseBody
public String commonParam(@RequestParam("name") String username , String age){
System.out.println("普通的参数传递--->"+username);
System.out.println("普通的参数传递--->"+age);
return "{module: 'common Param'}";
}
7.2、请求参数
-
名称:@RequestParam
-
类型:形参注解
-
位置:springMVC控制器方法形参定义前面
-
作用:绑定请求参数与处理器方法形参间的关系
-
//普通参数,请求参数与形参不同 @RequestMapping("/ordinary") @ResponseBody public String commonParam(@RequestParam("name") String username , String age){ System.out.println("普通的参数传递--->"+username); System.out.println("普通的参数传递--->"+age); return "{module: 'common Param'}"; }
7.3、pojo参数
-
请求参数名与形参对象属性名相同,定义pojo类型形参即可接收参数
//pojo参数
@RequestMapping("/pojo")
@ResponseBody
public String pojo(User user){
System.out.println("pojo参数传递--->"+user);
return "{module: 'pojo'}";
}
7.4、pojo嵌套参数
- 请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套pojo属性参数
//pojo参数嵌套使用
@RequestMapping("/pojop")
@ResponseBody
public String pojo2(User user){
System.out.println("pojo参数传递--->"+user);
return "{module: 'pojo2'}";
}
7.5、数组参数
-
请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型形参即可接收参数
//数组参数
@RequestMapping("/array")
@ResponseBody
public String array(String[] likes){
System.out.println("数组参数传递--->"+ Arrays.toString(likes));
return "{module: 'array'}";
}
7.6、集合参数
- 集合保存普通参数:请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam绑定关系
//集合参数
@RequestMapping("/list")
@ResponseBody
public String list(@RequestParam List<String> likes){
System.out.println("集合参数传递--->"+ likes);
return "{module: 'list'}";
}
8、json数据传递参数
-
增加json数据转换相应的坐标
<dependency> <groupId>mvn_resp.com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.3</version> </dependency>
-
增加json数据发送请求
-
开启自动转化json数据的支持
@Configuration @ComponentScan("com.anle.controller") @EnableWebMvc public class SpringMvcConfig { }
注意:@EnableWebMvc功能强大,该注解整合了多个功能,此处仅用其中的一部分共功能,即json数据进行自动类型转换
-
设置接收json数据
@RequestMapping("/listJson") @ResponseBody public String listJson(@RequestBody List<String> likes){ System.out.println("集合参数传递--->"+ likes); return "{module: 'listJson'}"; }
9、日期型参数传递
-
日期类型数据基于系统不同格式也不尽相同
- 2023-01-01
- 2023/01/01
- 01/01/2023
-
接收参数时,根据不同的日期格式设置不同的接收方式
//日期参数 @RequestMapping("/date") @ResponseBody public String date(Date date, @DateTimeFormat(pattern = "yyy-mm-dd") Date date1, @DateTimeFormat(pattern = "yyy/mm/dd hh:mm:ss") Date date2){ System.out.println("日期参数传递date--->"+date); System.out.println("日期参数传递date1 yyy-mm-dd--->"+date1); System.out.println("日期参数传递date2 yyy/mm/dd hh:mm:ss--->"+date2); return "{module: 'date'}"; }
访问参数:http://localhost:8080/req/date?date=2023/01/01&date1=2023-01-01&date2=2023/08/01 8:08:08
-
@DateTimeFormat注解
-
类型:形参注解
- 位置:springMVC控制器方法形参前面
- 作用:设定日期时间型数据格式
- 属性:pattern:日期时间格式字符串
-
类型转换器
- Convertor接口
- 请求年龄数据(String->Integer)
- 日期格式转换(String—>Date)
- Convertor接口
-
@EnablWedMvc功能之一:根据类型匹配对应的类型转换器
10、响应
10.1、响应页面
//响应页面/跳转页面
@RequestMapping("/a")
public String toJumPage() {
System.out.println("跳转页面");
return "hello.jsp";
}
-
注意这里看可能出现404报错可能时tomcat导包的问题,我们可以进入项目结构中进行查看。
10.2、响应文本数据
//响应文本
@RequestMapping("/b")
@ResponseBody
public String toTextPage() {
System.out.println("响应文本");
return "hello text";
}
10.3、响应json数据
//响应pojo集合对象
@RequestMapping("/d")
@ResponseBody
public List<User> toPojoArrayPage() {
System.out.println("返回json数据集合对象");
User user1 = new User();
user1.setName("张三");
user1.setAge(18);
User user2 = new User();
user2.setName("李四");
user2.setAge(19);
List<User> userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
return userList;
}
@ResponseBody注解
-
类型:方法注解
-
位置:springMVC控制器方法定义上方
-
作用:设置当前控制器返回值作为响应体
-
HttpMessageConverter接口:主要就是这个接口进行数据的转换,前面的转换的接口都是它的子类。
11、REST风格
11.1、简介:
- REST(Representational String Transfer),表现形式状态转换
- 传统风格资源描述形式
- http://localhost/user/getById?id=1
- http://localhost/user/saveUser
- REST风格描述形式
- http://localhost/user/1
- http://localhost/user
- 传统风格资源描述形式
- 优点:
- 隐藏资源的访问行为,无法通过地址得到资源是何种操作
- 书写简化
- 按照REST风格访问资源时使用行为动作区分对资源进行了何种操作
- 查询全部用户信息 GET (查询)
- 查询指定用户信息 GET (查询)
- 增加用户信息 POST (新增/保存)
- 修改用户信息 PUT(修改/更新)
- 删除用户信息 DELETE (删除)
- 根据REST风格对资源进行访问称为RESTful
注意:–上述行为是约定方式,约定不是规范,可以打破的,所以称为REST风格
11.2、REST入门案列
-
设定http请求动作(动词)
@RequestMapping(value = "/users",method = RequestMethod.PUT) @ResponseBody public String update(@RequestBody User user) { System.out.println("user update..."+user); return "{'module':'user update'}"; }
-
设置请求参数
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE) @ResponseBody public String delete(@PathVariable Integer id) { System.out.println("user delete..."+id); return "{'module':'user delete'}"; }
-
@RequestMapping注解
- 类型:方法注解
- 位置:springMVC控制器方法定义上方
- 作用:设置当前控制器方法请求访问路径
- 属性:
- value(默认):请求访问路径
- method:http请求动作,标准动作(GET/POST/DELETR/PUT)
-
@PathVariable
- 类型:形参注解
- 位置:springMVC形参定义前面
- 作用:绑定路劲参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应
@RequestBody @RequestParam @PathVariable
- 区别
- @RequestBody用于接收json数据
- @RequestParam用于接收url地址传参或者表单传参
- @PathVariable用于接收路径参数,使用(参数名称)描述路径参数
- 应用
- 后期开发中,发送请求参数超过1个小时,以json格式,@RequestBody应用比较广泛
- 如果发送非json数据,选用 @RequestParam接收请求参数
- 采用RESTful进行开发时,当参数数量比较少时,列如1个,可以采用 @PathVariable接收请求路劲变量,通常用于传递id值
11.3、REST快速注解开发
-
@RestController
- 类型:类注解
- 位置:基于springMVC的RESTful开发控制器类定义上方
- 作用:设置当前控制器为RESTful风格,等同于@Controller与@ResponseBody两个注解组合功能
@RestController public class BookController { }
-
@GetMapping @PostMapping @DeleteMapping @PutMapping
-
类型:方法注解
-
位置:基于springMvc的RESTful开发控制器方法定义上方
-
作用:设置当前控制器方法请求访问路径与请求动作,每种对应一个动作。
-
属性:value(默认):请求访问路径
实列:
/** * @author: anle * @date: 2023/04/26 09:36 **/ @RestController @RequestMapping("/books") public class BookController { @PostMapping public String save(@RequestBody Book book) { System.out.println("book...save"+book); return "{'module': 'save'}"; } @DeleteMapping("/{id}") public String delete(@PathVariable Integer id) { System.out.println("book..delete"+id); return "{'module': 'delete'}"; } @PutMapping public String update(@RequestBody Book book){ System.out.println("update..book"+book); return "{'module': 'update'}"; } @GetMapping("/{id}") public String getById(@PathVariable Integer id){ System.out.println("book getById"+id); return "{'module': 'getById'}"; } @GetMapping() public String getAll() { System.out.println("book getAll"); return "{'module': 'getAll'}"; } }
-
12、springmvc-SSM整合
12.1、ssm-整合(整体配置)
-
首先我们先创建一个maven模块
-
在pom.xml中导入对应的依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.anle</groupId> <artifactId>spring-mvc</artifactId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>springmvc-09-ssm-demo</artifactId> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency> </dependencies> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> </project>
-
在创建出对应的包结构
-
在config包中增加配置
springConfig
/** * @author: anle * @date: 2023/05/01 10:42 **/ @Configuration @ComponentScan({"com.anle.service"}) @PropertySource("classpath:jdbc.properties") @Import({JdbcConfig.class, MyBatisConfig.class}) public class SpringConfig { }
我们在这个项目里面需要用到数据库所有要配置我们的数据库
JdbcConfig
/** * @author: anle * @date: 2023/05/01 10:44 **/ public class JdbcConfig { public class jdbcConfig { //1、定义一个方法获得要管理的对象 //2、@Bean、表示当前方法的返回值是一个bean @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean public DataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; } } }
MybatisConfig
public class MyBatisConfig { @Bean public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){ SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); factoryBean.setTypeAliasesPackage("com.anle.pojo"); return factoryBean; } @Bean public MapperScannerConfigurer mapperScannerConfigurer(){ MapperScannerConfigurer msc = new MapperScannerConfigurer(); msc.setBasePackage("com.anle.dao"); return msc; } }
ServletConfig
/** * @author: anle * @date: 2023/05/01 10:54 **/ public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } }
SpringMvcConfig
/** * @author: anle * @date: 2023/05/01 10:55 **/ @Configuration @ComponentScan("com.anle.controller") @EnableWebMvc public class SpringMvcConfig { }
-
创建pojo实体类,更具数据库字段创建
/** * @author: anle * @date: 2023/05/01 11:19 **/ public class Book { private Integer id; //图书id private String type; //图书类型 private String name; //图书名字 private String description; //图书描述 public Book() { } public Book(Integer id, String type, String name, String description) { this.id = id; this.type = type; this.name = name; this.description = description; } /** * 获取 * @return id */ public Integer getId() { return id; } /** * 设置 * @param id */ public void setId(Integer id) { this.id = id; } /** * 获取 * @return type */ public String getType() { return type; } /** * 设置 * @param type */ public void setType(String type) { this.type = type; } /** * 获取 * @return name */ public String getName() { return name; } /** * 设置 * @param name */ public void setName(String name) { this.name = name; } /** * 获取 * @return description */ public String getDescription() { return description; } /** * 设置 * @param description */ public void setDescription(String description) { this.description = description; } public String toString() { return "Book{id = " + id + ", type = " + type + ", name = " + name + ", description = " + description + "}"; } }
-
创建dao层接口
/** * @author: anle * @date: 2023/05/01 11:21 **/ public interface BookDao { /** * @return 增加图书 * @param book */ @Insert("insert into tb_book(type,name,description) values(#{type},#{name}),#{description}") public void save(Book book); /** * @return 修改图书 * @param book */ @Update("update tb_book set type = #{type}, name = #{name} ,description = #{description} where id = #{id}") public void update(Book book); /** * @return 根据id删除 * @param id */ @Delete("delete from tb_book where id = #{id}") public void delete(Integer id); /** * @return 根据id查询 * @param id */ @Select("select id from tb_book where id = #{id}") public Book getBookById(Integer id); /** * @return 查询所有 * @param */ @Select("select id from tb_book ") public List<Book> getAll(); }
- 创建service层接口和实现类
/** * @author: anle * @date: 2023/05/01 11:22 **/ public interface BookService { /** * @return 增加图书 * @param book */ public boolean save(Book book); /** * @return 修改图书 * @param book */ public boolean update(Book book); /** * @return 根据id删除 * @param id */ public boolean delete(Integer id); /** * @return 根据id查询 * @param id */ public Book getBookById(Integer id); /** * @return 查询所有 * @param */ public List<Book> getAll(); }
实现类:
/** * @author: anle * @date: 2023/05/01 11:22 **/ @Service public class BookServiceImpl implements BookService { @Autowired private BookDao bookDao; @Override public boolean save(Book book) { bookDao.save(book); return true; } @Override public boolean update(Book book) { bookDao.update(book); return true; } @Override public boolean delete(Integer id) { bookDao.delete(id); return true; } @Override public Book getBookById(Integer id) { return bookDao.getBookById(id); } @Override public List<Book> getAll() { return bookDao.getAll(); } }
-
controller层
/**
* @author: anle
* @date: 2023/05/01 11:23
**/
@RestController
@RequestMapping("books")
public class BookController {
@Autowired
private BookService bookService;
@PostMapping
public boolean save(@RequestBody Book book) {
return bookService.save(book);
}
@PutMapping
public boolean update(@RequestBody Book book) {
return bookService.update(book);
}
@DeleteMapping("/{id}")
public boolean delete(@PathVariable Integer id) {
return bookService.delete(id);
}
@GetMapping("/{id}")
public Book getBookById(@PathVariable Integer id) {
return bookService.getBookById(id);
}
@GetMapping
public List<Book> getAll() {
return bookService.getAll();
}
}
12.2、ssm-整合(接口测试)
-
在test目录下创建一个测试类
/** * @author: anle * @date: 2023/05/07 16:36 **/ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class) public class BookServiceTest { @Autowired private BookService bookService; @Test public void testGetById(){ Book book = bookService.getBookById(1); System.out.println(book); } @Test public void testGetAll(){ List<Book> all = bookService.getAll(); System.out.println(all); } }
12.3、ssm-整合(表现层与前端页面数据传输)
-
前端接收数据格式—创建结果模型类,封装数据到data属性中
-
前端接收数据格式—封装操作结果得到的code属性中
-
前端接收数据格式—封装特殊消息到message(msg)属性中
-
设置统一数据返回结果类
public class Result { private Object data; private Integer code; private String msg; }
-
注意==== Result类中的字段并不是固定的,可以根据需要自行增减提供若干个构造方法,方便操作。
-
表现层与前端进行实现
-
在controller包下创建一个Result类
/** * @author: anle * @date: 2023/05/08 16:26 **/ public class Result { private Object data; 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; } /** * 获取 * @return data */ public Object getData() { return data; } /** * 设置 * @param data */ public void setData(Object data) { this.data = data; } /** * 获取 * @return code */ public Integer getCode() { return code; } /** * 设置 * @param code */ public void setCode(Integer code) { this.code = code; } /** * 获取 * @return msg */ public String getMsg() { return msg; } /** * 设置 * @param msg */ public void setMsg(String msg) { this.msg = msg; } public String toString() { return "Result{data = " + data + ", code = " + code + ", msg = " + msg + "}"; } }
-
还需要创建一个Code状态码类,后面为1表示为成功,为0表示失败
/** * @author: anle * @date: 2023/05/08 16:29 **/ public class Code { public static final Integer SAVE_OK =2011; //增加成功 public static final Integer DELETE_OK =2021;//删除成功 public static final Integer UPDATE_OK =2031;//修改成功 public static final Integer GET_OK =2041;//查询成功 public static final Integer SAVE_ERR =2010; //增加成功 public static final Integer DELETE_ERR =2020;//删除成功 public static final Integer UPDATE_ERR =2030;//修改成功 public static final Integer GET_ERR =2040;//查询成功 }
-
重新书写我们的controller层的BookController
/** * @author: anle * @date: 2023/05/01 11:23 **/ @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 getBookById(@PathVariable Integer id) { Book book = bookService.getBookById(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); } }
我们的返回值有所改变,这样前端就可以根据不同的请求得到对应的数据
-
12.4、smm-整合(异常处理)
- 出现异常现象得常见位置与常见原因如下:
- 框架内部抛异常:因使用不合格导致
- 数据层抛异常:因外部服务器故障导致(列如:服务器超时)
- 业务层抛出异常:因业务逻辑书写错误导致(列如:不匹配的数据类型间导致异常)
- 工具类抛出的异常:因为工具类书写不严谨不够导致(”必须释放连接长期未释放等“)
思考:==各个阶层均出现异常,异常处理代码书写在哪一层
—所有的异常抛出到表现层进行处理
- 异常处理器
- 集中的、统一的处理项目中出现的异常
/**
* @author: anle
* @date: 2023/05/09 09:45
**/
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(Exception.class)
public Result doException(){
System.out.println("异常抓到你了");
return new Result(666,null,"异常抓到你了");
}
}
- 名称: @ExceptionHandler
- 类型:方法注解
- 位置:专用于异常处理的控制器方法上方
- 作用:设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原始控制器执行,并转让当前执行
- 说明:
- 此类方法可以根据处理异常不同,制作多个方法分别处理对应的异常。
12.5、smm-整合(项目中的异常处理)
==项目异常分类:
- 业务异常(BusinessException)
- 规范的用户行为产生的异常
- 不规范的用户行为操作产生的异常
- 系统异常(SystemException)
- 项目运行过程中可预计且无法避免的异常
- 其他异常(Exception)
- 编程人员未预测到的异常
==项目异常处理方法:
- 业务异常(BusinessException)
- 发送对应消息传递给用户,提醒规范操作
- 系统异常(SystemException)
- 发送固定请求消息传递给用户,安抚用户
- 发送特定消息给运维人员,提醒维护
- 记录日志
- 其他异常(Exception)
- 发送固定请求消息传递给用户,安抚用户
- 发送固定消息给编程人员,提醒维护(纳入预期范围内)
- 记录日志
=====操作:
- 自定义项目系统异常
/**
* @author: anle
* @date: 2023/05/10 14:47
**/
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;
}
}
-
自定义项目业务异常
/** * @author: anle * @date: 2023/05/10 14:47 **/ 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; } }
-
自定义异常编码
-
触发自定义异常
-
拦截并处理异常
13、拦截器
13.1、拦截器概念:
- 拦截器是一种动态拦截方法调用的机制,在SpringMVC中动态拦截器控制方法的执行
- 作用:
- 在指定的方法调用前后执行预先设定的代码
- 阻止原始方法执行
13.2、拦截器与过滤器的区别
- 归属不同: Filter属于servlet技术,Intrcptor属于SpringMVC 技术、
- 拦截内容不同:Filter对所有访问进行增强,Intrcptor仅针对SpringMVC的访问进行增强
13.3、拦截器入门
-
声明拦截器的bean,并实现HandInterceptor接口(注意扫描bean,建议写在Conrtoller包下)
/** * @author: anle * @date: 2023/05/16 20:59 **/ @Component public class ProjectInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle...."); 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"); } }
-
定义配置类,继承WebMvcConfigurationSupport,实现addInterceptor方法,增加拦截器并设定拦截器的访问路径,路劲可以通过可变传输设置多个(注意:扫描加载配置)
/** * @author: anle * @date: 2023/05/16 21:04 **/ @Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { @Autowired private ProjectInterceptor projectInterceptor; @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(projectInterceptor).addPathPatterns("/books/*","/books"); } }
13.4、拦截器的参数
-
前置处理
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String type = request.getHeader("type"); System.out.println("preHandle...."+ type); return true; }
-
参数
- request:请求对象
- response:响应对象
- handler:被调用的处理器对象,本质上是一个方法对象,对反射技术中的Method对象进行了再包装
-
返回值:
- 返回值为false,被了解处理器将不在执行
-
后置对象
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle"); }
-
参数
- modelAndView:如果处理器执行完成具有返回结果,可以读取对应数据与页面的信息,并进行调整
-
完成后处理:
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion"); }
-
参数
- ex :如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理
13.5、拦截器链配置
-
当配置多个拦截器时,形成拦截器链
-
拦截器链的运行顺序参照拦截器增加顺序为准
-
当拦截器中出对原始处理器拦截均终止运行
-
当拦截器运行中断,仅运行配置在前面的拦截器afterCompletion操作
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion"); }
}
-
定义配置类,继承WebMvcConfigurationSupport,实现addInterceptor方法,增加拦截器并设定拦截器的访问路径,路劲可以通过可变传输设置多个(注意:扫描加载配置)
/** * @author: anle * @date: 2023/05/16 21:04 **/ @Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { @Autowired private ProjectInterceptor projectInterceptor; @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(projectInterceptor).addPathPatterns("/books/*","/books"); } }
13.4、拦截器的参数
-
前置处理
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String type = request.getHeader("type"); System.out.println("preHandle...."+ type); return true; }
-
参数
- request:请求对象
- response:响应对象
- handler:被调用的处理器对象,本质上是一个方法对象,对反射技术中的Method对象进行了再包装
-
返回值:
- 返回值为false,被了解处理器将不在执行
-
后置对象
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle"); }
-
参数
- modelAndView:如果处理器执行完成具有返回结果,可以读取对应数据与页面的信息,并进行调整
-
完成后处理:
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion"); }
-
参数
- ex :如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理
13.5、拦截器链配置
- 当配置多个拦截器时,形成拦截器链
- 拦截器链的运行顺序参照拦截器增加顺序为准
- 当拦截器中出对原始处理器拦截均终止运行
- 当拦截器运行中断,仅运行配置在前面的拦截器afterCompletion操作