SpringMVC
简介
mvc:指的是三层架构
m:model模型层
v:view视图层
c:controller控制层
springmvc是spring的后续产品,作用于控制层。
入门案例
1、创建maven的web项目
2、导入依赖
<!--导入springmvc所需的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<!--配置前端控制器时如果报错才配置-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
3、web.xml中配置前端控制器
<!--
如果不指定springmvc的配置文件名称和路径,此时web容器启动时,
会自动到WEB-INF下去找springmvc的配置文件 ===><servlet-name>标签的值+"-servlet.xml"
-->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--通过初始化参数改变springmvc项目的配置文件所在位置及配置文件名称-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--如果springmvc项目中的url-pattern配置成/时,
后续必须在springmvc的配置文件中进行相应的操作,
否则就会导致静态资源无法访问 ====>静态资源映射
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
4、编写配置文件
处理器映射器、处理器适配器
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.woniuxy.controller"/>
<!--配置处理器映射器:用于解析用户请求-->
<bean id="requestMappingHandlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<!--配置处理器适配器:用于根据处理器映射器的解析结果匹配具体的业务控制器方法-->
<bean id="requestMappingHandlerAdapter"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
<!--配置视图解析器:将逻辑视图名解析为一个物理视图-->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
5、编写业务控制器
@Controller//被注解的类型会作为控制器注册到容器中
public class UserController {
//用户发送的请求: http://localhost:8080/login
@RequestMapping("login")
public String login(){
System.out.println("执行了登录操作");
return "main";//逻辑视图名
}
}
入门案例分析
静态资源映射
如果dispatcherServlet的url-pattern配置的/,那么项目中所有的静态资源都将无法访问,需要去配置静态资源映射来解决此问题。
在springmvc的配置文件中进行以下配置即可。
<!--
静态资源映射
请求URL :http://localhost:8080/images/ring_5.jpg
mapping :用于匹配请求 /images/** 从请求URL中就匹配到了 /images/ring_5.jpg
location :用于指定一个具体位置 /images/ring_5.jpg
-->
<mvc:resources mapping="/images/**" location="/images/"/>
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/html/**" location="/html/"/>
绑定请求参数
1.基本数据类型和String
1.1.简单类型
对于基本数据类型和String,spring提供了对应的类型转换器,只要传递的值能够被转换为处理器方法上的形参类型,那么spring会自动帮你实现转换的过程。如果传递的值不能够被转换为对应的类型,此时,会抛出400。
对于字符串转换为日期,spring提供的类型转换器只能识别/连接符,不能识别其他连接符,就一定会抛出异常。此时需要自定义类型转换器来解决这个问题。
自定义类型转换器需要实现一个spring提供的接口:converter
String2Date
package com.woniuxy.converter;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 自定义类型转换器:将字符串转换为日期类型
*/
public class String2Date implements Converter<String, Date> {
/**
* 进行类型转换
* @param source :要被转换的数据
* @return
*/
@Override
public Date convert(String source) {
//实现转换逻辑
Date date = null;
String pattern1="[0-9]{4}-[0-9]{2}-[0-9]{2}";
String pattern2="[0-9]{4}/[0-9]{2}/[0-9]{2}";
try {
if (source.matches(pattern1)) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
date = format.parse(source);
} else if (source.matches(pattern2)) {
SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");
date = format.parse(source);
}
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
配置文件
<!--将自定义类型转换器加入到spring的类型转换器集合中-->
<bean id="conversionService2" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.woniuxy.converter.String2Date"/>
</set>
</property>
</bean>
<!--spring3.1版本之后,使用了<mvc:annotation-driven/>来替换处理器映射器和处理器适配器的配置,功能比单独配置处理器映射器和处理器适配器更强大-->
<!--主动使用添加了自定义类型转换器的conversionService2-->
<mvc:annotation-driven conversion-service="conversionService2"/>
1.2.同名参数的绑定
以数组的形式进行参数绑定,可以直接绑定进来
但是,如果以集合的方式进行绑定,此时要注意两点:
1、不能使用集合的接口类型(因为接口没有构造方法),只能使用集合的实现类,
2、在处理器方法形参上还需要加上@RequestParam注解,才可以完成参数绑定。
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/login" method="get">
<table>
<tr>
<td>用户名</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密码</td>
<td><input type="text" name="password"></td>
</tr>
<tr>
<td>年龄</td>
<td><input type="text" name="age"></td>
</tr>
<tr>
<td>出生日期</td>
<td><input type="date" name="birthday"></td>
</tr>
<tr>
<td>爱好</td>
<td>
<input type="checkbox" name="hobbies" value="吃饭">吃饭
<input type="checkbox" name="hobbies" value="睡觉">睡觉
<input type="checkbox" name="hobbies" value="打豆豆">打豆豆
</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="立即登录"></td>
</tr>
</table>
</form>
</body>
</html>
业务控制器
package com.woniuxy.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Controller//被注解的类型会作为控制器注册到容器中
public class UserController {
//用户发送的请求: http://localhost:8080/login
@RequestMapping("login")
//进行参数绑定时,需要保证处理器方法的形参名称与用户请求中附带的参数的key
//hobbies可以直接使用数组来绑定请求参数,String[] hobbies
//集合则应该使用@RequestParam ArrayList<String> hobbies
public String login(String username, String password,
Double age, Date birthday,
@RequestParam ArrayList<String> hobbies){
System.out.println("执行了登录操作");
System.out.println(username);
System.out.println(password);
System.out.println(++age);
System.out.println(birthday);
for (String hobby : hobbies) {
System.out.println(hobby);
}
return "main";//逻辑视图名
}
}
处理请求中文乱码
在web.xml中配置spring提供的字符编码过滤器
<!--配置字符编码过滤器:可以解决请求中文乱码问题--> <filter> <filter-name>charset</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> </filter> <filter-mapping> <filter-name>charset</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2.javaBean
当请求参数个数非常多时,在处理器方法上以形参方式进行绑定,会造成代码可读性降低。因此,当请求参数个数超过5个时,建议使用javaBean来完成参数绑定。
要求:javaBean的属性名称必须和请求参数名称保持一致。
/**
* 作用:用于绑定请求参数的。
*/
@Data
public class UserVO {
String username;
String password;
Integer age;
Date birthday;
List<String> hobbies;
}
业务控制器
@Controller
public class UserController {
@RequestMapping("login")
public String login(UserVO userVO){
System.out.println("执行了登录操作");
System.out.println(userVO);
return "main";
}
}
4.获取Servlet API
程序中要使用servlet api时,可以直接在处理器形参中使用对应的servlet api来进行绑定,此时可以直接在处理器方法内部使用对应的对象。
/**
* 获取servlet-api
* http://localhost:8080/register?username=tom
* @return
*/
@RequestMapping("register")
public String register(HttpServletRequest request, HttpServletResponse response, HttpSession session){
System.out.println(request);
System.out.println(request.getParameter("username"));
System.out.println(response);
System.out.println(session);
System.out.println(session.getServletContext());
return "main";
}
5.restful风格参数绑定
http://localhost:8080/login/tom/111
百度百科
/**
* restful风格参数绑定 :路径传参
* http://localhost:8080/query/tom/111
* @return
*/
@RequestMapping("query/{username}/{password}")
public String query(@PathVariable String username, @PathVariable String password){
System.out.println("执行了登录操作");
System.out.println(username+":"+password);
return "main";
}
6.ajax传递的参数绑定
6.1 非json字符串
与普通的参数绑定方式一致。
6.2 json字符串
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="/js/jquery-3.3.1.js"></script>
</head>
<body>
<form id="myForm" action="/login" method="get">
<table>
<tr>
<td>用户名</td>
<td><input type="text" name="username" id="username"></td>
</tr>
<tr>
<td>密码</td>
<td><input type="text" name="password" id="password"></td>
</tr>
<tr>
<td>年龄</td>
<td><input type="text" name="age"></td>
</tr>
<tr>
<td>出生日期</td>
<td><input type="text" name="birthday"></td>
</tr>
<tr>
<td>爱好</td>
<td>
<input type="checkbox" name="hobbies" value="吃饭">吃饭
<input type="checkbox" name="hobbies" value="睡觉">睡觉
<input type="checkbox" name="hobbies" value="打豆豆">打豆豆
</td>
</tr>
<tr>
<td colspan="2"><input type="button" value="立即登录" id="btn"></td>
</tr>
</table>
</form>
<script>
$(function () {
$("#btn").click(function () {
//如果ajax请求提交的数据不是json字符串,与其他的参数绑定方式完全一致
//如果ajax请求提交的数据是一个json字符串,则处理方式完全不同
//传递json字符串时,需要进行四个操作
//1、导入jackson-databind(该依赖导入会同时导入jackson-core、jackson-annotations)
//2、在处理器形参的javaBean前加@RequestBody
//3、发送请求的方式只能是POST
//4、发送请求时应指定请求的内容类型是application/json;charset=utf-8
var user={
username:$("#username").val(),
password:$("#password").val()
}
$.ajax({
url:"/login",
data:JSON.stringify(user),
type:"POST",
contentType:"application/json;charset=utf-8",
dataType:"json",
success:function (respData) {
console.log(respData)
}
})
})
})
</script>
</body>
</html>
响应返回值
springmvc给用户的响应是通过处理器方法的返回值来决定的。
void:开发过程中基本不用。因为方法返回值为void时,该方法就没有return进行返回,此时会基于处理器方法上的@RequestMapping的值作为逻辑视图名去找视图解析器,并进行相应的处理。
/**
* 一般不用
* 方法无返回值,此时,会基于@RequestMapping("say")的值say作为逻辑视图名,
* 去找视图解析器进行相应处理
*/
@RequestMapping("say")
public void say(){
System.out.println("执行了say方法");
}
object:
ModelAndView
/**
* ModelAndView: 封装了模型和视图的一个类型
* @return
*/
@RequestMapping("query")
public ModelAndView query(){
User user = new User("tom", "111");
ModelAndView mv = new ModelAndView();
mv.addObject("user",user);//使用ModelAndView对象来保存数据,数据存放在requst域中
mv.setViewName("main");//设置视图名
return mv;
}
普通object
/**
* 直接返回某个类型的对象,此时,还是将@RequestMapping("user")的值user作为逻辑视图名,
* 去找视图解析器进行相应处理
* 如果在处理器方法上加上@ResponseBody,则会将方法的返回值转换为son字符串并返回出去,
* 不会再走视图解析器
* @return
*/
@RequestMapping("user")
@ResponseBody//作用:将方法的返回值转换为json字符串并返回出去,不会再走视图解析器
public User getUser(){
return new User("tom","111");
}
使用dto来完成统一返回格式
@Data
@AllArgsConstructor
public class Result<T> {
private Boolean flag;//标识前端对后台发起的请求是否操作成功
private String code;//设置一个业务状态码
private String message;//用于描述当前操作的具体信息
private T data;//用于保存返回给用户的实际数据
}
public class StatusCode {
public static final String SUCCESS="20000";//表示业务执行成功的状态
public static final String PASSWORDERROR="20007";//密码错误
public static final String UNKOWNUSERNAME="20008";//账户尚未注册
}
业务控制器中
@Controller
public class StudentController {
/**
* dto d: data t:transfer o:object :用于统一返回格式
*
* vo v:value o:object :用于封装用户传递的参数
*
*/
@GetMapping("student")
@ResponseBody
public Result query(){
//表示去查询到了用户
User user = new User("tom", "111");//是从数据库中查询得到的
return new Result(true, StatusCode.SUCCESS,"查询用户成功",user);
}
@PutMapping("student")
@ResponseBody
public Result update(){
try {
System.out.println("执行了修改操作");
// System.out.println(1/0);
return new Result(true, StatusCode.SUCCESS,"修改用户成功",null);
} catch (Exception e) {
e.printStackTrace();
return new Result(false, StatusCode.PASSWORDERROR,"修改用户失败",null);
}
}
String:特殊的一种
逻辑视图 :返回的是逻辑视图时,会走视图解析器,最终去匹配一个物理视图,匹配上了就正常返回了该视图,如果没有匹配上,就返回404。
@RequestMapping("login")
public String login(){
System.out.println("执行了登录操作");
return "main";
}
物理视图 : 返回的如果是物理视图时,必带关键字。forward(请求转发) redirect(重定向)
返回物理视图名:
/**
* forward: 默认值 请求转发
* redirect: 重定向
* 如果处理器方法返回值希望跳转到一个物理视图时,也不能不写关键字,
*
* 也就是说,如果处理器方法的返回值上不带关键字时,都会走视图解析器
*
* @return
*/
@RequestMapping("update")
public String update(){
System.out.println("执行了update操作");
return "forward:/main.jsp";
}
返回另一个处理器方法的@RequestMapping的值
/**
* ModelAndView: 封装了模型和视图的一个类型
* @return
*/
@RequestMapping("query")
public ModelAndView query(String username){
System.out.println(username);//null
User user = new User("tom", "111");
ModelAndView mv = new ModelAndView();
mv.addObject("user",user);//使用ModelAndView对象来保存数据,数据存放在requst域中
mv.setViewName("main");//设置视图名
return mv;
}
/**
* @return
*/
@RequestMapping("update")
public String update(){
System.out.println("执行了update操作");
return "forward:query";
}
Restful风格接口设计
rest请求:
GET ====>查询操作
POST ====>新增操作
PUT ====>修改操作
DELETE ====>删除操作
restful风格就是基于rest请求去调用业务控制器中不同的数据接口。
只是一种接口设计风格,而不是规范和规则,也就是说,不遵守该风格,程序是不会报错的。
对于一份资源(user),在后台(控制器中)增删改查的操作,对该资源的映射值只会有一个(也就是说不管是执行增、删、改、查的哪种操作,@RequestMapping的值只会有一个)。
要严格遵守restful风格进行接口设计时,会认为访问后台的都是一份一份的资源,因为@RequestMapping中的值只能出现名词,不能出现动词。因为restful风格认为对资源进行的操作应该由请求的提交方式来决定,而不是资源名称来决定。
设计案例
package com.woniuxy.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
/**
* 该控制器操作应该是对teacher这个类型的资源
* restful风格的设计,此时,增删改查4个方法的@RequestMapping的值只能有一个。
*/
@Controller
@RequestMapping("teacher")
public class TeacherController {
// @RequestMapping(value = "teacher",method = RequestMethod.POST)
@PostMapping("name") //http://localhost:8080/teacher/name
public String add(){
System.out.println("add");
return "redirect:/html/add.html";
}
// @RequestMapping(value = "teacher",method = RequestMethod.PUT)
@PutMapping
public String update(){
System.out.println("update");
return "redirect:/html/update.html";
}
// @RequestMapping(value = "teacher",method = RequestMethod.DELETE)
@DeleteMapping
public String delete(){
System.out.println("delete");
return "redirect:/html/delete.html";
}
// @RequestMapping(value = "teacher",method = RequestMethod.GET)
@GetMapping
public String query(){
System.out.println("query");
return "redirect:/html/query.html";
}
}
幂等性:
对同一个数据接口进行多次调用,产生的结果不会破坏数据和发生数据更改。只要满足该条件,则认为该接口满足幂等性。
对于rest请求来说,除post请求以外,其余的都满足幂等性。
文件上传和文件下载
文件上传
springmvc将文件域(input标签)封装为一个MultipartFile对象,通过该对象即可完成文件的上传操作。底层的文件上传逻辑是通过commons-fileupload组件来完成的,所以,要实现文件上传,应该导入该依赖。
1、导入依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
2、编写前端页面
<form action="/user/register" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="username"><br>
密码:<input type="text" name="password"><br>
上传文件:<input type="file" name="upload"><br>
<input type="submit" value="立即提交">
</form>
3、编写控制器上传接口
@RequestMapping("register")
@ResponseBody
public Result register(User user, MultipartFile upload) throws IOException {
System.out.println(user);
String path="D:\\files".replace("\\", File.separator);//上传文件的存储位置
String randomStr = UUID.randomUUID().toString();
String filename = upload.getOriginalFilename();//获取上传文件的原始名称
String fileType=filename.substring(filename.lastIndexOf("."));
String saveFileName=randomStr+fileType;//对上传文件的保存名称进行处理
File saveFile = new File(path, saveFileName);
upload.transferTo(saveFile);
return new Result(true, StatusCode.SUCCESS,"上传成功",null);
/**
*
*
* 文件上传实现步骤:
* 1、导入commons-fileupload依赖
* 2、编写上传页面:表单的提交方法只能是post,enctype="multipart/form-data",文件域必须指定name属性
* 3、编写接口,接口的形参MultipartFile来接收文件域的内容
* 3.1指定文件存储路径
* 3.2处理上传文件同名的问题
* 3.3使用MultipartFile对象调用transferTo方法将内容传输到上传的文件中
* 4、配置文件中配置CommonsMultipartResolver,id只能是multipartResolver
* 在该bean指定上传文件的最大尺寸 maxuploadsize #{}
*
*
*
*/
}
4、配置文件
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="#{100*1024*1024}"/>
</bean>
文件下载
content-disposition :attachment(附件形式)
springmvc提供了一个ResponseEntity(响应实体),用于封装响应头、响应状态、文件内容。
下载测试页面
<a href="/user/download?filename=菜谱.txt">菜谱</a>
业务控制器中处理下载操作的接口
/**
* 执行下载操作
* @return
*/
@RequestMapping("download")
public ResponseEntity download(String filename) throws IOException {
//文件内容
String path="D:\\files".replace("\\", File.separator);
File downloadFile = new File(path, filename);
//使用commons-io组件中的api将文件内容读取到内存中
byte[] bytes = FileUtils.readFileToByteArray(downloadFile);
//处理文件名的中文乱码
filename=URLEncoder.encode(filename,"UTF-8");
//响应头信息
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition","attachment;filename="+filename);
//响应状态码
HttpStatus status = HttpStatus.OK;
//创建responseEntity对象时,需要提供三个参数:文件内容、响应头信息、响应状态码
ResponseEntity responseEntity = new ResponseEntity(bytes,headers,status);
return responseEntity;
}
异常处理
自定义异常处理
springmvc提供了HandlerExceptionResolver接口以提供异常处理。只需要创建一个类实现该接口,就可以完成springmvc控制器接口中的异常处理。
测试页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="/js/jquery-3.3.1.js" type="text/javascript"></script>
</head>
<body>
<form action="/user/login" method="get">
<input type="submit" value="测试普通请求"/>
</form>
<input type="button" id="btn" value="测试ajax请求"/>
<script>
$(function () {
$("#btn").click(function () {
$.ajax({
url:"/user/login",
type:"get",
success:function (resp) {
console.log(resp)
}
})
})
})
</script>
</body>
</html>
自定义异常处理类
package com.woniuxy.exception;
import com.alibaba.fastjson.support.spring.FastJsonJsonView;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
/**
* 自定义异常处理器:
* springmvc提供HandlerExceptionResolver接口,只要创建类实现该接口就可以完成自定义的异常处理了。
*/
@Component
public class MyExceptionHandler implements HandlerExceptionResolver {
/**
* 自定义异常处理的方法
* @param request :请求对象
* @param response :响应对象
* @param handler :异常处理对象
* @param ex :异常对象
* @return :modelandview
*/
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
//建议在这里将异常信息打印出来,便于排错
ex.printStackTrace();
ModelAndView mv = new ModelAndView();
//先判断用户提交的请求是否是ajax请求
if (StringUtils.hasLength(request.getHeader("X-Requested-With"))) {//ajax
//借助于fastJson来产生一个jsonView,将这个视图返回js域
FastJsonJsonView jsonView = new FastJsonJsonView();
HashMap<String, String> map = new HashMap<>();
map.put("message","系统繁忙,请稍候再使用");
jsonView.setAttributesMap(map);
mv.setView(jsonView);
}else{//非ajax
mv.setViewName("error");
}
return mv;
}
}
业务控制器接口
@Controller
@RequestMapping("user")
public class UserController {
@RequestMapping("login") //http://localhost:8080/user/login
public Result login(){
System.out.println(1/0);
return new Result(true, StatusCode.SUCCESS,"登录成功",null);
}
}
全局异常处理
使用全局异常处理可以针对性的去处理某个具体的异常。
借助于spring提供的两个注解:@RestControllerAdvice @ExceptionHandler就可以完成全局异常配置。
全局异常总类:
package com.woniuxy.exception;
import com.woniuxy.dto.Result;
import com.woniuxy.dto.StatusCode;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理空指针异常
* @return
*/
@ExceptionHandler(NullPointerException.class)
public Result handleNullPointerException(){
return new Result(false, StatusCode.ERROR,"空指针异常",null);
}
/**
* 处理算术异常
* @return
*/
@ExceptionHandler(ArithmeticException.class)
public Result handleArithmeticException(){
return new Result(false, StatusCode.ERROR,"算术异常",null);
}
/**
* 兜底操作:处理所有异常
* @return
*/
@ExceptionHandler(Exception.class)
public Result handleException(Exception e){
e.printStackTrace();
return new Result(false, StatusCode.ERROR,"服务器异常",null);
}
}
拦截器
springmvc中有一个很重要的控件叫拦截器,该控件作用于前端控制器和业务控制器之间。拦截器的作用有点类似于过滤器。
springmvc提供了一个接口HandleInterceptor,实现该接口就可以创建一个拦截器,拦截器中有3个方法,preHandle()、postHandle()、afterCompletion(),这三方法决定了拦截器的运行过程。
preHandle():控制器方法执行之前执行
postHandle():控制器方法执行之后执行
afterCompletion():控制器方法执行之后,且渲染了页面之后再执行
如果项目中存在多个拦截器,拦截器的执行顺序以配置文件中的配置顺序来决定。
在配置文件中可以通过mvc:interceptors标签来配置拦截器,来指定拦截器的行为。
拦截器
FirstInterceptor
package com.woniuxy.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 拦截器:
* 1、创建拦截器
*/
public class FirstInterceptor implements HandlerInterceptor {
/**
* 在业务控制器的接口方法执行之前执行的方法
* @param request
* @param response
* @param handler
* @return 方法返回值是一个boolean,如果返回true,放行,如果返回false,拦截
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("FirstInterceptor preHandle...");
return true;
}
/**
* 在业务控制器的接口方法执行之后再执行的方法
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("FirstInterceptor postHandle...");
}
/**
* 在业务控制器的接口方法执行之后,并且进行视图渲染之后再执行的方法
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("FirstInterceptor afterCompletion...");
}
}
SecondInterceptor
package com.woniuxy.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 拦截器:
* 1、创建拦截器
*/
public class SecondInterceptor implements HandlerInterceptor {
/**
* 在业务控制器的接口方法执行之前执行的方法
* @param request
* @param response
* @param handler
* @return 方法返回值是一个boolean,如果返回true,放行,如果返回false,拦截
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("SecondInterceptor preHandle...");
return true;
}
/**
* 在业务控制器的接口方法执行之后再执行的方法
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("SecondInterceptor postHandle...");
}
/**
* 在业务控制器的接口方法执行之后,并且进行视图渲染之后再执行的方法
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("SecondInterceptor afterCompletion...");
}
}
配置文件
<!--
配置拦截器:
-->
<mvc:interceptors>
<!--指定拦截的规则-->
<mvc:interceptor>
<!--指定要被拦截的路径 :配置黑名单
http://localhost:8080/user/login
-->
<mvc:mapping path="/user/**"/>
<!--指定不被拦截的路径 :配置白名单-->
<mvc:exclude-mapping path="/user/login"/>
<!--当mvc:mapping的path从请求URL中匹配到具体的路径之后,
就会使用具体的一个类型来处理被拦截的路径-->
<bean class="com.woniuxy.interceptor.FirstInterceptor"/>
</mvc:interceptor>
<!--指定拦截的规则-->
<mvc:interceptor>
<!--指定要被拦截的路径 :配置黑名单
http://localhost:8080/user/login
-->
<mvc:mapping path="/user/**"/>
<!--指定不被拦截的路径 :配置白名单-->
<mvc:exclude-mapping path="/user/login"/>
<!--当mvc:mapping的path从请求URL中匹配到具体的路径之后,
就会使用具体的一个类型来处理被拦截的路径-->
<bean class="com.woniuxy.interceptor.SecondInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
登录验证
拦截器
package com.woniuxy.interceptor;
import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 登录验证的拦截器
*/
public class LoginInterceptor implements HandlerInterceptor {
/**
* 在preHandle()中编写登录验证的逻辑
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object loginUser = request.getSession().getAttribute("loginUser");
if (ObjectUtils.isEmpty(loginUser)) {//未登录状态
response.sendRedirect("/html/login.html");
return false;
}else{//登录状态
return true;
}
}
}
配置文件
<!--
配置拦截器:
-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/teacher/login"/>
<mvc:exclude-mapping path="/teacher/register"/>
<mvc:exclude-mapping path="/html/login.html"/>
<mvc:exclude-mapping path="/html/register.html"/>
<mvc:exclude-mapping path="/html/index.html"/>
<bean class="com.woniuxy.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
参数校验
参数校验分为两个部分:
前端:验证的参数的传递格式
后台:针对非正常的向后台发送的请求,进行参数校验
参数校验使用的是JSR303校验方式,官方推荐的实现是hibernate validator。
1、导入依赖
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.5.Final</version>
</dependency>
2、在参数对象的成员变量上使用对应的注解来指定校验规则
package com.woniuxy.vo;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Pattern;
@Data
public class UserVo {
@Length(min = 6,max = 20,message = "用户名字段的长度必须在6-20位之间")
private String username;
@Min(value = 1,message = "年龄不能小于1岁")
@Max(value = 120,message = "年龄不能大于120岁")
private Integer age;
@Pattern(regexp = "[0-9a-zA-Z_]{6,12}@[0-9a-zA-Z_]{2,8}(\\.[a-z]{2,10}){1,2}",message = "邮箱格式不正确")
private String email;
}
3、业务控制器的接口必须使用javaBean来接收参数,在参数对象前加@Valid注解,表示进行参数绑定时必须做参数校验,校验结果保存在一个紧临参数对象之后的BindingResult对象中。
/**
* 在接收参数的javaBean前加一个@Valid注解,表示进行参数绑定时,要经过校验
* bindingResult对象必须紧临接收参数的javaBean,用于接收参数校验结果
* @param userVo
* @return
*/
@RequestMapping("login")
public String login(@Valid UserVo userVo, BindingResult bindingResult){
if (bindingResult.hasErrors()) {//如果校验结果中出现了错误,则表示参数校验失败
List<ObjectError> errors = bindingResult.getAllErrors();//获取参数校验出现的错误
errors.forEach(error->{
System.out.println(error.getDefaultMessage());
});
}
System.out.println("执行了登录操作");
return "main";
}
项目中参数校验的使用
1、自定义异常:该异常在参数校验未通过时抛出
/**
* 用于参数校验失败时抛出的异常
*/
public class ParameterException extends Exception {
}
2、业务控制器的接口方法中,如果bindingResult.hasErrors()方法返回值为true时,抛出自定义异常
@RequestMapping("login")
public String login(@Valid UserVo userVo, BindingResult bindingResult) throws ParameterException {
if (bindingResult.hasErrors()) {//如果校验结果中出现了错误,则表示参数校验失败
throw new ParameterException();
}
System.out.println("执行了登录操作");
return "main";
}
3、在全局异常总类中,对自定义异常进行处理。
@RestControllerAdvice
public class GlobalExceptionHandler {
//处理自定义异常
@ExceptionHandler(ParameterException.class)
public Result handleParameterException(){
return new Result(false,"20010","参数异常",null);
}
@ExceptionHandler(Exception.class)
public Result handleException(){
return new Result(false,"20010","服务器异常",null);
}
}
SSM整合(spring+springmvc+mybatis)
父子容器
进行ssm整合时,可以让spring和springmvc使用同一个配置文件,但此时一个配置文件要服务于两个框架,会导致配置文件职责不明确,代码可读性差的问题出现,因此实现开发过程中,我们会将spring部分的操作放在spring的配置文件中,springmvc部分的操作配置在springmvc的配置文件中。
如果以两个配置文件来分别描述两个框架的内容,此时需要注意父子容器(spring容器为父容器,springmvc为子容器)带来的问题:父子容器都去扫描了相同的包下的注解,此时不管是controller也好,service也好,会同时在父子容器中各存在一份,此时如果项目中使用了声明式事务,则声明式事务会失效。
因此,在SSM整合时,需要去考虑父子容器带来的问题。我们需要让spring扫描所有的注解,但排除Controller注解不扫,让springmvc只扫描Controller注解,其他注解不扫,此时即可保证项目中所有被注解的类在容器中只有一个对象,从而可以解决声明式事务失效的问题。
整合
整合之XML
spring整合mybatis
applicationContext.xml
<!--表示spring应该扫描com.woniuxy包下的所有注解,但把@Controller注解给排除掉,让springmvc去扫-->
<context:component-scan base-package="com.woniuxy">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
spring整合springmvc
springmvc.xml
<!--表示指定springmvc只去扫描com.woniuxy.controller下的@Controller注解
注意:base-package必须指向controller层,如果配置成com.woniuxy,springmvc一样的也会扫描对应包下的所有注解
-->
<context:component-scan base-package="com.woniuxy.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
web.xml配置父子容器启动顺序
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--spring提供了监听器,监听servletContext对象的创建,此时会读取context-param配置的初始化参数,从而读取spring的配置文件生成spring容器,保证了父容器创建在子容器之前-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>springmvc</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>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
完整案例:实现转账业务,使用了声明式事务,使用了全局异常处理。
model层
@Data
public class Account {
private Integer id;
private String username;
private Double balance;
}
mapper层
public interface AccountMapper {
@Select("select * from account where username=#{username}")
Account findByUserName(String username);
@Update("update account set balance=#{balance} where username=#{username}")
void updateAccount(Account account);
}
service层
public interface AccountService {
Account findByUserName(String username);
void transfer(String source,String target,Double money);
}
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Resource
private AccountMapper accountMapper;
@Override
public Account findByUserName(String username) {
return accountMapper.findByUserName(username);
}
@Override
public void transfer(String source, String target, Double money) {
Account sourceAccount = accountMapper.findByUserName(source);
Account targetAccount = accountMapper.findByUserName(target);
if (sourceAccount.getBalance() > money) {
sourceAccount.setBalance(sourceAccount.getBalance()-money);
targetAccount.setBalance(targetAccount.getBalance()+money);
accountMapper.updateAccount(sourceAccount);
System.out.println(1/0);
accountMapper.updateAccount(targetAccount);
}else{
throw new RuntimeException("余额不足");
}
}
}
controller层
@RestController
@RequestMapping("account")
public class AccountController {
@Resource
private AccountService accountService;
@RequestMapping("find")
public Result find(String username){
Account account = accountService.findByUserName(username);
return new Result(true,"20000","查询用户成功",account);
}
@RequestMapping("transfer")
public Result transfer(AccountVO accountVO){
accountService.transfer(accountVO.getSource(),accountVO.getTarget(),accountVO.getMoney());
return new Result(true,"20000","转账成功",null);
}
}
参数对象VO
@Data
public class AccountVO {
private String source;
private String target;
private Double money;
}
数据传输对象DTO
@Data
@AllArgsConstructor
public class Result<T> {
private Boolean flag;
private String code;
private String message;
private T data;
}
全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ArithmeticException.class)
public Result handleArithmeticException(){
return new Result(false,"20009","算术异常",null);
}
@ExceptionHandler(Exception.class)
public Result handleException(){
return new Result(false,"20010","服务器异常",null);
}
}
applicationContext.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--表示spring应该扫描com.woniuxy包下的所有注解,但把@Controller注解给排除掉,让springmvc去扫-->
<context:component-scan base-package="com.woniuxy">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///bank?characterEncoding=utf-8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.woniuxy.mapper"/>
</bean>
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
<tx:attributes>
<tx:method name="*" read-only="false" propagation="REQUIRED"/>
<tx:method name="find" read-only="true" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="pt" expression="execution(* com.woniuxy.service.impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
</aop:config>
</beans>
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
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--表示指定springmvc只去扫描com.woniuxy.controller下的@Controller注解
注意:base-package必须指向controller层,如果配置成com.woniuxy,springmvc一样的也会扫描对应包下的所有注解
-->
<context:component-scan base-package="com.woniuxy.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<mvc:annotation-driven/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/html/"/>
<property name="suffix" value=".html"/>
</bean>
<mvc:resources mapping="/html/**" location="/html/"/>
</beans>
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--spring提供了监听器,监听servletContext对象的创建-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>springmvc</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>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
测试页面
查询
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/account/find" method="get">
<input type="text" name="username">
<input type="submit" value="立即查询">
</form>
</body>
</html>
转账
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>转账页面</title>
</head>
<body>
<form action="/account/transfer" method="get">
转出账户:<input type="text" name="source"><br>
转入账户:<input type="text" name="target"><br>
转出金额:<input type="text" name="money"><br>
<input type="submit" value="立即转账">
</form>
</body>
</html>
整合之注解
spring整合mybatis
使用配置类替换spring的配置文件
package com.woniuxy.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
/**
* spring的配置类,用于代替applicationContext.xml
*/
@Configuration
@ComponentScan(basePackages = {"com.woniuxy"},useDefaultFilters = true,
excludeFilters = {
@ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
)
}
)//指定spring要去扫描哪些注解,排除了@Controller注解
@MapperScan("com.woniuxy.mapper")//用于替换mapperScannerConfigurer
@EnableTransactionManagement
@PropertySource(value = "classpath:jdbc.properties",ignoreResourceNotFound = true)
public class SpringConfig {
@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(){
System.out.println("DataSource init...");
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
System.out.println("SqlSessionFactoryBean init...");
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean;
}
@Bean
public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource){
System.out.println("DataSourceTransactionManager init...");
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
}
spring整合springmvc
注意:先创建maven的web项目,再将webapp目录删掉。
使用配置类来替换springmvc的配置文件
package com.woniuxy.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@ComponentScan(basePackages = {"com.woniuxy.controller"},useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
)
}
)//指定springmvc去扫描哪个包下的注解,只扫描了@Controller
@EnableWebMvc//
public class SpringMvcConfig implements WebMvcConfigurer {
/**
* 静态资源映射
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
System.out.println("addResourceHandlers");
//<mvc:resources mapping="/html/**" location="/html/"/>
registry.addResourceHandler("/html/**").addResourceLocations("classpath:/html/");
}
/**
* 视图解析器配置
* @param registry
*/
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
System.out.println("configureViewResolvers");
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/html/");
resolver.setSuffix(".html");
registry.viewResolver(resolver);
}
}
替换web.xml
使用配置类来替换web.xml
package com.woniuxy.config;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.*;
import java.util.EnumSet;
/**
* 该类用于替代web.xml
* 该类的onStartup()中需要进行三个配置:
* 1、代替监听器去读取spring的配置类
* 2、代替前端控制器去读取springmvc的配置类
* 3、注册字符编码过滤器
*/
public class WebConfig implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
/*************************spring相关配置**************************/
//创建spring的web容器
AnnotationConfigWebApplicationContext spring = new AnnotationConfigWebApplicationContext();
//注册spring的配置类
spring.register(SpringConfig.class);
//使用监听器监听spring的web容器的创建
servletContext.addListener(new ContextLoaderListener(spring));
/*************************springmvc相关配置**************************/
//创建springmvc的web容器
AnnotationConfigWebApplicationContext springmvc =new AnnotationConfigWebApplicationContext();
//注册springmvc的配置类
springmvc.register(SpringMvcConfig.class);
//创建前端控制器对象
ServletRegistration.Dynamic dispatcherServlet = servletContext.addServlet("dispatcherServlet",
new DispatcherServlet(springmvc));
//设置前端控制器的初始化时机
dispatcherServlet.setLoadOnStartup(1);
//设置前端控制器匹配的url-pattern
dispatcherServlet.addMapping("/");
/*************************字符编码过滤器配置**************************/
FilterRegistration.Dynamic charset = servletContext.addFilter("charset",
new CharacterEncodingFilter("UTF-8"));
EnumSet<DispatcherType> dispatcherTypes = EnumSet.noneOf(DispatcherType.class);
dispatcherTypes.add(DispatcherType.REQUEST);
dispatcherTypes.add(DispatcherType.FORWARD);
charset.addMappingForUrlPatterns(dispatcherTypes,true,"/*");
}
}
跨域
方法一:在控制层类上 @CrossOrigin
方法二:在SpringMVC注解开发上 重写addCorsMappings(CorsRegistry registry)
@Override
public void addCorsMappings(CorsRegistry registry){
registry.addMapping("/**") //匹配请求的url
.allowedHeaders("*") //允许那些头能够跨域
.allowedOrigins("*") //允许哪些源能够跨域
.allowedMethods("*") //允许哪些提交方法可以跨域访问
.allowCredentials(true) //允许请求中附带cookie信息
.maxAge(3600); //跨域访问超时时间
}
de
public void onStartup(ServletContext servletContext) throws ServletException {
/*************************spring相关配置**************************/
//创建spring的web容器
AnnotationConfigWebApplicationContext spring = new AnnotationConfigWebApplicationContext();
//注册spring的配置类
spring.register(SpringConfig.class);
//使用监听器监听spring的web容器的创建
servletContext.addListener(new ContextLoaderListener(spring));
/*************************springmvc相关配置**************************/
//创建springmvc的web容器
AnnotationConfigWebApplicationContext springmvc =new AnnotationConfigWebApplicationContext();
//注册springmvc的配置类
springmvc.register(SpringMvcConfig.class);
//创建前端控制器对象
ServletRegistration.Dynamic dispatcherServlet = servletContext.addServlet("dispatcherServlet",
new DispatcherServlet(springmvc));
//设置前端控制器的初始化时机
dispatcherServlet.setLoadOnStartup(1);
//设置前端控制器匹配的url-pattern
dispatcherServlet.addMapping("/");
/*************************字符编码过滤器配置**************************/
FilterRegistration.Dynamic charset = servletContext.addFilter("charset",
new CharacterEncodingFilter("UTF-8"));
EnumSet<DispatcherType> dispatcherTypes = EnumSet.noneOf(DispatcherType.class);
dispatcherTypes.add(DispatcherType.REQUEST);
dispatcherTypes.add(DispatcherType.FORWARD);
charset.addMappingForUrlPatterns(dispatcherTypes,true,"/*");
}
}
#### 跨域
方法一:在控制层类上 @CrossOrigin
方法二:在SpringMVC注解开发上 重写addCorsMappings(CorsRegistry registry)
```java
@Override
public void addCorsMappings(CorsRegistry registry){
registry.addMapping("/**") //匹配请求的url
.allowedHeaders("*") //允许那些头能够跨域
.allowedOrigins("*") //允许哪些源能够跨域
.allowedMethods("*") //允许哪些提交方法可以跨域访问
.allowCredentials(true) //允许请求中附带cookie信息
.maxAge(3600); //跨域访问超时时间
}