SpringBoot在Web应用中的知识点
本小记学习目标
-
SpringBoot项目War包的生成与Tomcat发布
-
https安全访问配置
-
SpringBoot中数据验证
-
错误页面的配置
-
全局异常处理
-
文件上传功能
-
拦截器
-
AOP拦截器
一、SpringBoot项目War包的生成与Tomcat发布
SpringBoot中默认支持Tomcat容器,当一个SpringBoot打包成为一个jar包并直接运行时会自动启动内部Tomcat容器,除了这种方式也可以把项目打包为war包,采用部署的形式,通过Tomcat进行发布处理。
如何把项目打成war包并在Tomcat中进行发布?
1.在xiaoxieboot项目上点击右键--->New--->Maven Module,建立一个新的Module:xiaoxieboot-web
2.在xiaoxieboot-web的项目中对pom.xml文件进行编辑
指定打包的方式为war
< packaging >war packaging >
新增相关的依赖
< dependencies >
< dependency >
< groupId > junit groupId >
< artifactId > junit artifactId >
< scope >test scope >
dependency >
< dependency >
< groupId >org.springframework.boot groupId >
< artifactId >spring-boot-starter-test artifactId >
< scope >test scope >
dependency >
< dependency >
< groupId >org.springframework.boot groupId >
< artifactId >spring-boot-starter-web artifactId >
dependency >
< dependency >
< groupId >org.springframework.boot groupId >
< artifactId >spring-boot- devtools artifactId >
dependency >
dependencies >
配置打包的方式
< build >
< plugins >
< plugin >
< groupId >org.apache.maven.plugins groupId >
< artifactId > maven-war- plugin artifactId >
< configuration >
< warName >xiaoxieboot-web warName >
configuration >
plugin >
plugins >
build >
3.我们需要更新Maven,项目上点击右键--->Maven--->Update Project...
4.手动新增WEB-INF/web.xml文件,如下图项目结构所示
对于web.xml要符合Tomcat容器的要求,内容如下
xml version= "1.0" encoding= "UTF-8" ?>
< web-app xmlns:xsi= " http://www.w3.org/2001/XMLSchema-instance " xmlns= " http://java.sun.com/xml/ns/javaee " xsi:schemaLocation= " http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd " id= "WebApp_ID" version= "2.5" />
5.新增SpringBoot程序启动类:com.xiaoxie.SpringBootStartApplication
package com.xiaoxie;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@ SpringBootApplication
public class SpringBootStartApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(SpringBootStartApplication. class);
}
public static void main(String[] args) {
SpringApplication. run(SpringBootStartApplication. class, args);
}
}
注意:我们要以war包在Tomcat中运行,那么这个启动类必须要继承SpringBootServletInitializer类,同时要覆盖configure()方法。
6.新增一个Controller包并新增Controller类,com.xiaoxie.controller.TestController
package com.xiaoxie.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@GetMapping( "/test")
public String test() {
return "TEST!!!";
}
}
7.把项目打包为war包,项目右键--->Run As--->Maven build...,在弹出的对话框中勾Skip Tests,Goals:中录入“clean package”
8.打包的过程在控制台会显示提示信息,如果正常打包完成,会在项目所在目录的target下生成一个war包,我们的war包为"xiaoxieboot-web.war"
9.把这个war包复制到Tomcat的webapps目录下,启动Tomcat,会自动对war包解压,同时在命令框提示信息中看到相应的启动信息
完成启动后访问:http://localhost:8080/xiaoxieboot-web/test
在页面中可以看到信息: TEST!!!
注意:访问时需要带上打包的名称xiaoxieboot-web(这个名称是在pom.xml中打war的配置中设置的)
二、https安全访问配置
SpringBoot启动时默认使用的是http通信,为了保证安全通常需要使用https来进行访问。
通常来说,https的访问是需要证书的,并且为了保证这个证书的安全,一定要在项止中使用CA进行认证。
1.使用JDK中的keytool命令生成证书 keystore.p12,命令如下:
keytool -genkey -alias mytomcat -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore D:/keystore.p12 -validity 3650 -dname "CN=Web Server,OU=Unit,O=Organization,L=City,S=State,C=US" -storepass P@ssw0rd
2.通过上面的命令则在D盘下生成了一个证书:keystore.p12
把这个证书复制到项目的src/main/resources/resources目录下
同时在这个目录下新增配置文件application.yml
server:
port: 433 #https的端口设置为433
ssl:
key-store: classpath:keystore.p12 #keystore配置文件路径
key-store-type: PKCS12 #keystore的类型为PKCS12
key-alias: mytomcat #设置别名
key-store-password: P@ssw0rd #访问别名
3.在pom.xml的打包配置文件中对资源的访问添加p12类型,在内部下添加
< resources >
< resource >
< directory > src/main/resources directory >
< includes >
< include >**/*.properties include >
< include >**/*. yml include >
< include >**/*. xml include >
< include >**/*. tld include >
< include >**/*.p12 include >
includes >
< filtering >false filtering >
resource >
resources>
4.新增一个配置类,以便于用户访问80端口的时候跳转到安全链接433端口上
package com.xiaoxie.config;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class HttpConnectorConfig {
public Connector initConnector() {
Connector connector = new Connector( "org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme( "http");
connector.setPort(80);
connector.setSecure( false);
connector.setRedirectPort(433);
return connector;
}
@Bean
public TomcatServletWebServerFactory servletContainerFactory() {
TomcatServletWebServerFactory tswf = new TomcatServletWebServerFactory() {
protected void postProcessContext(Context context) {
//定义安全访问策略
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint( "CONFIDENTIAL"); //定义用户访问约束要求
SecurityCollection collection = new SecurityCollection();
collection.addPattern( "/*"); //匹配所有访问路径
securityConstraint.addCollection( collection); //追加路径映射访问配置
context.addConstraint( securityConstraint);
}
};
tswf.addAdditionalTomcatConnectors(initConnector());
return tswf;
}
}
三、SpringBoot中数据验证
SpringBoot中的验证可以使用hibernate-vidator组件包实现验证处理,这个组件包支持的验证注解如下:
注解
|
描述
|
@Null
|
被注解的元素必须为null
|
@NotNull
|
被注解的元素不为null
|
@AssertTrue
|
被注解的元素必须为true
|
@Min(value)
|
被注解的元素必须为一个数值,且必须要大于等于指定的值
|
@Max(value) |
被注解的元素必须为一个数值,且必须要小于等于指定的值
|
@DecimalMin(value)
|
被注解的元素必须为一个数值,且必须要大于等于指定的值
|
@DecimalMax(value)
|
被注解的元素必须为一个数值,且必须要小于等于指定的值
|
Size(max=,min=)
|
被注解的元素大小必须在指定的范围内
|
@Digits(integer,fraction)
|
被注解的元素必须是一个数字,其值 必须在可接受的范围内
|
@Past
|
被注解的元素必须是一个过去的日期
|
@Future
|
被注解的元素必须是一个将来的日期
|
@Pattern(regex=,flag=)
|
被注解的元素必须符合指定的正则表达式
|
@NotBlank(message=)
|
被注解的元素字符串非null,且长度必须大于0
|
@Email
|
被注解的元素必须是电子邮箱地址
|
@Length(min=,max=)
|
被注解的字符串的长度必须在指定范围内
|
@NotEmpty
|
被注解的字符串必须非空
|
@Range(min=,max=,message=)
|
被注解的元素必须在合适的范围内
|
1.在项目中新增错误提示信息的资源文件,ValidationMessages.properties 在src/main/resources目录下
注意:这里资源文件的名称必须是:ValidationMessages.properties,同时要注意使用ISO-8859-1的文件编码(SpringBoot 2.0 默认就是使用这个格式去读取资源文件的)
employee.no.notnull.error= 员工编号不可以为空
employee.no.email.error= 员工编号必须使用正确的邮箱
employee.name.notnull.error= 员工名称不可以为空
employee.post.notnull.error= 员工岗位不可以为空
employee.joinDate.past.error= 员工的入职日期不可以大于当前时间
employee.salary.digits.error= 员工的薪资必须是数值
2.新增一个vo类:com.xiaoxie.vo.Employee
package com.xiaoxie.vo;
import java.util.Date;
import javax.validation.constraints.Digits;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
public class Employee {
@NotNull(message= "{employee.no.notnull.error}")
@Email(message= "{employee.no.email.error}")
private String no; //员工编号
@NotNull(message= "{employee.name.notnull.error}")
private String name; //员工姓名
@NotNull(message= "{employee.post.notnull.error}")
private String post; //员工所在岗位
@Past(message= "{employee.joinDate.past.error}")
private Date joinDate; //员工入职日期
@Digits(integer=20,fraction=2,message= "{employee.salary.digits.error}")
private Double salary; //基本工资
public String getNo() {
return no;
}
public void setNo(String no) {
this. no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this. name = name;
}
public String getPost() {
return post;
}
public void setPost(String post) {
this. post = post;
}
public Date getJoinDate() {
return joinDate;
}
public void setJoinDate(Date joinDate) {
this. joinDate = joinDate;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this. salary = salary;
}
}
从上面可以看到,在属性上添加了注解验证
3.新增一个Controller类,com.xiaoxie.controller.EmployeeController
package com.xiaoxie.controller;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.Iterator;
import javax.validation.Valid;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.xiaoxie.vo.Employee;
@Controller
public class EmployeeController {
@GetMapping( "/input_emp")
public String input() {
return "input_emp";
}
@PostMapping( "/save_emp")
@ResponseBody
public Object save( @Valid Employee emp,BindingResult result) {
if( result.hasErrors()) { //验证存在错误
Iterator iterator = result.getAllErrors().iterator();
while( iterator.hasNext()) { //遍历所有错误
ObjectError error = iterator.next();
//在控制台打印错误信息
System. out.println( "错误信息--->Code:"+ error.getCode() + " ,message:" + error.getDefaultMessage());
}
return result.getAllErrors();
} else { //没有错误的情况
return emp;
}
}
@InitBinder
public void initBinder(WebDataBinder wdb) {
//对日期格式化处理
SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd");
//注册一个日期格式化处理程序类
wdb.registerCustomEditor(Date. class, new CustomDateEditor( sdf, true));
}
}
对于方法input,它是跳转到Thymeleaf的模板页面input_emp.html,这时需要新增一包src/main/view/templates,并在其下新增模板页面input_emp.html
DOCTYPE html>
< html xmlns= " http://thymeleaf.org " >
< head >
< meta charset= "UTF-8" >
< title >新增一个员工 title >
head >
< body >
< h2 >新增员工 h2 >
< form th:action= "@{save_emp}" method= "post" >
员工编码: < input type= "text" name= "no" />< span style=" color: gary;" >(请使用邮箱) span >
员工姓名: < input type= "text" name= "name" />
员工岗位: < input type= "text" name= "post" />
入职日期: < input type= "text" name= "joinDate" />
员工薪资: < input type= "text" name= "salary" />
< input type= "submit" value= "提交" />
< input type= "reset" value= "重置" />
form >
body >
html >
在上面的页面中可以看到表单提交时提交到/save_emp,它对应到控制器类的save方法。
四、错误页面的配置
当我们程序出现错误时,为了给用户展现一个友好的错误提示页面,我们需要配置对应的错误信息提示页。错误提示页面一般来说属于静态页面。
1.在src/main/view/static目录下我们新增两个页面error-404.html、error-500.html
error-404.html
DOCTYPE html>
< html >
< head >
< meta charset= "UTF-8" >
< title >错误提示 title >
head >
< body >
< h2 >404,页面消失了~~~ h2 >
body >
html >
error-500.html
DOCTYPE html>
< html >
< head >
< meta charset= "UTF-8" >
< title >错误提示 title >
head >
< body >
< h2 >500,对不起让我先崩溃会~~ h2 >
body >
html >
2.新增错误页面的配置,com.xiaoxioe.Config.ErrorPageConfig
package com.xiaoxie.config;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistry;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
@Configuration
public class ErrorPageConfig implements ErrorPageRegistrar{
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
ErrorPage error404 = new ErrorPage(HttpStatus. NOT_FOUND, "/error-404.html");
ErrorPage error500 = new ErrorPage(HttpStatus. INTERNAL_SERVER_ERROR, "/error-500.html");
registry.addErrorPages( error404, error500);
}
}
通过上面的配置,当程序发生404,500错误时会跳转到指定的错误页面
五、全局异常处理
全局异常处理指的是针对程序中产生的Exception进行处理,当产生了异常后,可以跳转到指定的页面进行错误提示或者通过Restful的形式来返回错误信息。
1.建立一个全局的异常处理类,它可以处理所有的Exception异常,com.xiaoxie.advice.Exception
package com.xiaoxie.advice;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
@ControllerAdvice //控制层切面
public class ExceptionAdvice {
public static final String DEFAULT_ERROR_VIEW = "error"; //默认错误显示页面error.html
@ExceptionHandler
public ModelAndView defaultErrorHandler(HttpServletRequest request,Exception e) {
ModelAndView mav = new ModelAndView( DEFAULT_ERROR_VIEW); //设置跳转路径
//绑定相关数据
mav.addObject( "exception", e);
mav.addObject( "url", request.getRequestURL());
return mav;
}
}
2.上面默认的错误显示页面是error.html,所以在templates下新增error.html
DOCTYPE html>
< html xmlns= " http://thymeleaf.org " >
< head >
< meta charset= "UTF-8" >
< title >异常信息页面 title >
head >
< body >
< p th:text= "${'错误访问路径:'+url}" />
< p th:text= "${'错误信息:'+exception.message}" />
body >
html >
3.新增一个Controller,com.xiaoxie.controller.ExceptionController
package com.xiaoxie.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ExceptionController {
@GetMapping( "/cal/{num}")
public String cal( @PathVariable( "num") Integer num) {
int result = 100/ num;
return "100除以"+ num + "的结果是:" + result;
}
}
通过上面我们定义了一个请求路径/cal/{num},这里的num必须是Integer
当请求的路径为/cal/n时,页面显示内容如下:
错误访问路径:https://localhost:433/cal/n
错误信息:Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: "n"
当请求路径为/cal/0时,页面显示内容如下:
错误访问路径:https://localhost:433/cal/0
错误信息:/ by zero
当请请路径为/cal/10时,页面显示内容如下:
100除以10的结果是:10
如果我们需要以Restful的形式回应异常信息,则可以把全局的异常处理切面类修改为如下
@RestControllerAdvice
public class ExceptionAdvice{
@ExceptionHandler
public Object defaultErrorHandler(HttpServletRequest request,Exception e) {
ErrorInfo error = new ErrorInfo();
error.setCode(HttpStatus. INTERNAL_SERVER_ERROR.value());
error.setMessage( e.getMessage());
error.setUrl( request.getRequestURL().toString());
return error;
}
ErrorInfo新定的一个vo类
package com.xiaoxie.vo;
public class ErrorInfo {
private Integer code;
private String message;
private String url;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this. code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this. message = message;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this. url = url;
}
}
六、文件上传功能
SpringBoot本身是支持文件上传操作的,它采用了FileUpload组件实现文件的上传处理,在控制器中可以使用MultipartFile类进行接收处理。
1.新增一个控制器类 com.xiaoxie.controller.UploadController
package com.xiaoxie.controller;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
@Controller
public class UploadController {
//跳转到upload.html
@GetMapping( "/upload_pre")
public String uploadPre() {
return "upload";
}
@PostMapping( "/upload")
@ResponseBody
public Object upload(String name,MultipartFile photo) throws Exception {
Map map = new HashMap();
if( photo != null && photo.getSize() != 0) {
//这里说明有文件上传
map.put( "name-param", name);
map.put( "photo-name", photo.getName());
map.put( "content-type", photo.getContentType());
map.put( "photo-size", photo.getSize()); //按字节单位计算
//创建一个上传后保存的文件名称
String fileName = UUID. randomUUID() + "."+ photo.getContentType().substring( photo.getContentType().lastIndexOf( "/")+1);
//文件保存路径
String filePath = ((ServletRequestAttributes)RequestContextHolder. getRequestAttributes()).getRequest().getServletContext().getRealPath( "/") + fileName;
map.put( "photo-path", filePath);
File saveFile = new File( filePath);
//文件保存
photo.transferTo( saveFile);
return map;
} else {
return "nothing";
}
}
}
这里有两个方法一个是uploadPre方法,它的作用是用来做访问的跳转转发到upload.html页面上去;第二个是upload方法,它接收一个post请求用来处理文件上传
注意:MaltipartFile这个类,它封装了上传文件的信息
2.在src/main/view/template下新增一个upload.html页面
DOCTYPE html>
< html xmlns= " http://thymeleaf.org " >
< head >
< meta charset= "UTF-8" >
< title >上传文件 title >
head >
< body >
< form th:action= "@{/upload}" method= "post" enctype= "multipart/form-data" >
名称: < input type= "text" name= "name" />< br />
图片: < input type= "file" name= "photo" />< br />
< input type= "submit" value= "上传" />
form >
body >
html >
在实际的开发过程中,一般是需要对用户上传文件的大小进行限制的,这样可以做到综合平衡服务器资源及用户需求。
可以在aplication.yml配置文件中新增上传限制
spring:
servlet:
multipart:
enabled: true
max-file-size: 10MB #设置单个文件的大小限制
max-request-size: 20MB #设置总体文件大小
file-size-threshold: 512KB #当上传文件达到指定配置量的时候,把文件内容写入磁盘
location: / #临时目录
除了上面的在配置文件中对上件文件大小进行配置,也可以添加Bean的配置类进行配置
在com.xiaoxie.config包下添加配置类UploadConfig
package com.xiaoxie.config;
import javax.servlet.MultipartConfigElement;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class UploadConfig {
@Bean
public MultipartConfigElement getMultipartConfig() {
MultipartConfigFactory config = new MultipartConfigFactory();
config.setMaxFileSize( "10MB");
config.setMaxRequestSize( "100MB");
config.setLocation( "/");
return config.createMultipartConfig();
}
}
注意:当配置aplication.yml配置文件和UploadConfig配置类都存在的时候,优先以配置类UploadConfig类中的配置来做校验
在实际开发中我们如果一次需要上传多个文件则需要使用MultipartHttpServletRequest进行文件接收
1.新增一个html的模板页面upload_m.html
DOCTYPE html>
< html xmlns= " http://thymeleaf.org " >
< head >
< meta charset= "UTF-8" >
< title >多个上传文件 title >
head >
< body >
< form th:action= "@{/upload_m}" method= "post" enctype= "multipart/form-data" >
名称: < input type= "text" name= "name" />< br />
图片1: < input type= "file" name= "photo" />< br />
图片2: < input type= "file" name= "photo" />< br />
图片3: < input type= "file" name= "photo" />< br />
< input type= "submit" value= "上传" />
form >
body >
html >
2.在UploadController类中新增两个Controller方法及一个文件的保存方法
//跳转到upload_m.html
@GetMapping( "/upload_pre_m")
public String uploadPrem() {
return "upload_m";
}
@PostMapping( "/upload")
@ResponseBody
public Object upload(String name,MultipartFile photo) throws Exception {
Map map = new HashMap();
if( photo != null && photo.getSize() != 0) {
//这里说明有文件上传
map.put( "name-param", name);
map.put( "photo-name", photo.getName());
map.put( "content-type", photo.getContentType());
map.put( "photo-size", photo.getSize()); //按字节单位计算
//创建一个上传后保存的文件名称
String fileName = UUID. randomUUID() + "."+ photo.getContentType().substring( photo.getContentType().lastIndexOf( "/")+1);
//文件保存路径
String filePath = ((ServletRequestAttributes)RequestContextHolder. getRequestAttributes()).getRequest().getServletContext().getRealPath( "/") + fileName;
map.put( "photo-path", filePath);
File saveFile = new File( filePath);
//文件保存
photo.transferTo( saveFile);
return map;
} else {
return "nothing";
}
}
@PostMapping( "/upload_m")
@ResponseBody
public Object uploadm(String name,HttpServletRequest request) {
List result = new ArrayList();
if( request instanceof MultipartHttpServletRequest) {
MultipartHttpServletRequest mrequest = (MultipartHttpServletRequest) request;
List files = mrequest.getFiles( "photo");
Iterator it = files.iterator();
while( it.hasNext()) {
//读取每一个上传的文件
MultipartFile photo = it.next();
//保存上传信息
try {
result.add(saveFile( photo));
} catch (Exception e) {
e.printStackTrace();
}
}
}
return result;
}
private String saveFile(MultipartFile file) throws Exception {
String path = "nothing";
if( file != null && file.getSize() > 0) {
String fileName = UUID. randomUUID() + "." + file.getContentType().substring( file.getContentType().lastIndexOf( "/")+1);
path = ((ServletRequestAttributes)RequestContextHolder. getRequestAttributes()).getRequest().getServletContext().getRealPath( "/") + fileName;
File saveFile = new File( path);
file.transferTo( saveFile);
}
return path;
}
}
注意:当多个文件上传过程中有一个不成功时都不会完成保存文件的操作
七、拦截器
Web请求处理的过程中,拦截器是服务器端进行数据处理的最后一道关卡,在这里可以对所有用户请求的信息做拦截验证。
1.在程序中新增一个拦截器的类:com.xiaoxie.interceptor.Myinterceptor,这个类需要实现拦截器类HandlerInterceptor
package com.xiaoxie.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
//自定义拦截器实现拦截器接口
public class MyInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory. getLogger(MyInterceptor. class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//在这里可以添加拦截器处理代码,在执行控制器之前执行,如果返回true则继续,返回false则不再继续请求
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// 拦截器处理代码
log.info( "MyInterceptor中postHandler=> " + modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
//拦截器处理代码
}
}
2.如果需要拦截器生效需要新增配置类,对MVC做配置,并在其中添加自定义的拦截器及指定匹配的地址,在com.xoiaoxie.config包下新增类MyWebApplicationConfig类,继承WebMvcConfigurationSupport类
package com.xiaoxie.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import com.xiaoxie.interceptor.MyInterceptor;
@Configuration
public class MyWebApplicationConfig extends WebMvcConfigurationSupport {
@ Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor( new MyInterceptor()).addPathPatterns( "/**"); //匹配路
super.addInterceptors( registry);
}
}
八、AOP拦截器
AOP:面向切面编程。它的主要功能就是对业务层的方法调用进行拦截处理,SpringBoot默认是没有含AOP拦截器的,如果需要使用则要在项目中添加sping-boot-starter-aop依赖
在使用AOP之前需要在pom.xml中新增如下依赖
< dependency >
< groupId >org.springframework.boot groupId >
< artifactId >spring-boot-starter- aop artifactId >
dependency >
1.新增一个Service接口:com.xiaoxie.service.IinfoService
package com.xiaoxie.service;
public interface IinfoService {
public String echo(String message);
}
2.新增service接口的实现类:com.xiaoxie.service.impl.InfoServiceImpl
package com.xiaoxie.service.impl;
import org.springframework.stereotype.Service;
import com.xiaoxie.service.IinfoService;
@Service
public class InfoServiceImpl implements IinfoService {
@Override
public String echo(String message) {
return "【ECHO】" + message;
}
}
3.新增一个切面类对业务代码进行拦截,com.xiaoxie.aspcet.ServiceAspect
package com.xiaoxie.aspect;
import java.util.Arrays;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class ServiceAspect {
private static final Logger log = LoggerFactory. getLogger(ServiceAspect. class);
@Around( "execution(* com.xiaoxie.service..*.*(..))")
public Object arroundInvoke(ProceedingJoinPoint point) throws Throwable{
log.info( "【serviceBefore】执行参数:"+Arrays. toString( point.getArgs()));
//具体的业务调用
Object obj = point.proceed( point.getArgs());
//返回结果
log.info( "【serviceAfter】返回结果:" + obj);
return obj;
}
}
4.编写测试类测试在业务层调用方法是的拦截是否生效,在src/test/java下新增类com.xiaoxie.test.InfoSeviceTest
package com.xiaoxie.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import com.xiaoxie.SpringBootStartApplication;
import com.xiaoxie.service.IinfoService;
@SpringBootTest(classes=SpringBootStartApplication. class)
@RunWith(SpringJUnit4ClassRunner. class)
@WebAppConfiguration
public class InfoServiceTest {
@Autowired
private IinfoService infoService;
@ Test
public void testinfo() {
System. out.println( infoService.echo( "SpringBoot-AOP拦截"));
}
}