-
先感慨一下:要改掉不做笔记的坏毛病呀! 先提一嘴:spring boot 配置 Filter 有两种方式,一种是编程方式(spring
boot 最开始支持的方式), 另一种是注解方式(spring boot 后来又加了的一种配置方式)。 这几个月加班实在厉害,
看了点东西,却没有做笔记, 后续会补上, 并且后面会一直做笔记了,也希望看到这篇博客的搬砖新老同志们也做做笔记啊!
之前在一个自己的练手项目中使用第一种配置方式配置过, 但是没有做笔记,今天又要配置了, 想了想看看以前的吧, 找了好久,就是没找到,
(不对呀!肯定配过, 怎么就没了呢!啊!!!) 言归正传 -
统一返回数据格式
统一返回数据格式, 顾名思义, 同一个项目中所有返回的数据格式相同, 使前端(iOS Android, Web)对数据的操作更轻松一些, 前台需要拿到后台返回到前台的状态信息, 来响应的做处理, 如通讯异常, 操作成功, 存储失败等!
统一返回数据格式也没有一个具体的格式, 只要能描述清楚返回数据状态以及要返回的具体数据就可以:
/**
- 统一返回实体
- - @author zhangchenzhao
- @create 2018-08-08 下午11:25
*/
public class ResponseData<T> {
/**
* @Author : Zcz
* @Description: 状态码
* @Date: 2018/8/19 - 下午2:48
*/
private String code;
/**
* @Author : Zcz
* @Description: 是否成功
* @Date: 2018/8/19 - 下午2:48
*/
private Boolean status;
/**
* @Author : Zcz
* @Description: 状态信息
* @Date: 2018/8/19 - 下午2:48
*/
private String msg; //
/**
* @Author : Zcz
* @Description: :返回数据
* @Date: 2018/8/19 - 下午2:47
*/
public T data;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Boolean getStatus() {
return status;
}
public void setStatus(Boolean status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public ResponseData(T data) {
this.code = "000000";
this.msg = "成功";
this.status = true;
this.data = data;
}
public ResponseData() {
this.code = "000000";
this.msg = "成功";
this.status = true;
}
public ResponseData(String code, Boolean status, String msg, T data) {
this.code = code;
this.status = status;
this.msg = msg;
this.data = data;
}
public ResponseData(ResponseEnum responseEnum, T data){
this.code = responseEnum.getCode();
this.status = responseEnum.getStatus();
this.msg = responseEnum.getMsg();
this.data = data;
}
public ResponseData(Exception e){
this.code = "000012";
this.status = false;
this.msg = e.getMessage();
}
@Override
public String toString() {
return "ResponseData{" +
"code='" + code + '\'' +
", status=" + status +
", msg='" + msg + '\'' +
", data=" + data +
'}';
}
}
- 我这里就只写了四个属性 code、status、msg、data 分别描述返回数据的状态码, 比如00000表示正确状态, 00001
表示数据存储更新失败, 00002表示数据删除失败等…; status是一个 Boolean 值, 前端若指向知道是否成功或失败,
不关心具体失败原因, 只用 status 做判断, msg 是信息描述, 简单描述此次通讯的信息, 如成功, 失败, 存储失败,
连接失败…等; data 这个属性最重要, 是前端需要的数据, 前端需要用这个数据做显示, 或重要操作, 但类型不定,
多以使用泛型表示
/**
* 返回信息枚举
* * @author zhangchenzhao
* @create 2018-08-08 下午11:42
*/
public enum ResponseEnum {
SUCCESS("000000", true, "成功"),
SAVE_ERROR("000001", false, "保存数据失败"),
DELETE_ERROR("000002", false, "删除数据失败"),
UPDATE_ERROR("000003", false, "更新数据失败"),
SELECT_ERROR("000004", false, "查询数据失败");
private String code;
private Boolean status;
private String msg;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Boolean getStatus() {
return status;
}
public void setStatus(Boolean status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
ResponseEnum(String code, Boolean status, String msg) {
this.code = code;
this.status = status;
this.msg = msg;
}
}
- 用枚举做一些常见返回类型的状态信息, 以便开发时使用!
- 下面是spring boot 做统一异常处理 统一异常处理, 我们在开发中,肯定会遇到抛出异常和捕获异常的代码,
以防止因为不必要的错误导致整个程序崩溃, 使程序作出异常记录,但程序仍能正常运行, 这里使用 filter
作为统一异常处理的拦截方式(话说原生的 filter和 listener 还是超好用的); 原理: filter 监听 servlet
的声明周期活动 init dofilter destory 三个方法***(init和 destory不知道它俩有啥鸟用,若有大神见到此废话, 希望留下箴言教诲, 以使小渣本人有所提高, 感激不尽)*** , 其中
dofilter(ServletRequest req, ServletResponse rsp, Filterchain chain)
这个方法及其重要,
- 前台发送Http请求, filter 会根据 uri 的匹配拦截相应的请求, 通过 filterChain.dofilter()放行,
处理实线部分的 Controller service dao 等操作, 当 controller 返回数据后就是
dofilter()处理接触, 继续 dofilter 后面的操作, 此时可以通过捕获 dofilter 的异常来统一处理所有
controller 执行操作的异常 第一种spring boot 代码方式配置 filter:
import com.bbuilder.personal.config.filter.UnifyExceptionFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
/**
* @author zhangchenzhao
*/
@SpringBootApplication
public class PersonalApplication {
public static void main(String[] args) {
SpringApplication.run(PersonalApplication.class, args);
}
@Bean
public FilterRegistrationBean exceptionFilter(){
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new UnifyExceptionFilter());
registration.addUrlPatterns("/*");
// registration.addInitParameter("paramName", "paramValue");
registration.setName("exceptionFilter");
registration.setOrder(1);
return registration;
}
}
- 使用@Bean 配置FilterRegistrationBean 过滤器注册 bean 到 springcontext 中,使过滤器生效
第二种方式 原生注解方式
/**
* @author zhangchenzhao
*/
@SpringBootApplication
@ServletComponentScan
public class PersonalApplication {
public static void main(String[] args) {
SpringApplication.run(PersonalApplication.class, args);
}
}
- 这里最终要的注解是 @ServletComponentScan, 他会扫描 application
启动同包,及以下子包中的注解@WebFilter @Order @WebInitParam() 等
/**
* 统一异常处理过滤器
*
* @author zhangchenzhao
* @create 2018-08-19 下午3:23
*/
@WebFilter(filterName = "exceptionFilter", urlPatterns = "/*")
@Order(1)
public class UnifyExceptionFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
try {
filterChain.doFilter(servletRequest ,servletResponse);
}catch (BaseException e){
exceptionDataHandel((HttpServletResponse)servletResponse, e);
}catch (Exception e){
exceptionDataHandel((HttpServletResponse)servletResponse, (BaseException) e);
}catch (Error error){
System.out.println(error.getCause());
}
}
/**
* @Author : Zcz
* @Description: 整理异常数据
* @Date: 2018/8/20 - 上午12:22
*/
public void exceptionDataHandel(HttpServletResponse response, BaseException e)
throws ServletException, IOException {
String msg = e.getMessage();
if(e.getObjects()!=null && e.getObjects().length != 0){
msg = msg+": [";
for (Object obj :
e.getObjects()) {
msg = msg + obj.toString()+",";
}
msg = msg .substring(0, msg.length()-1);
}
responseExceptionMsg(response, msg);
}
/**
* @Author : Zcz
* @Description: 返回异常时前端需要的数据
* @Date: 2018/8/20 - 上午12:22
*/
public void responseExceptionMsg(HttpServletResponse response, String msg)
throws ServletException, IOException {
response.getWriter().write(msg);
}
}
注:@webFilter 注解是servlet3.0的原生注解,并不是spring boot的注解, 但这种注册方式仍然是与代码配置方式相同
参考: https://blog.csdn.net/king_is_everyone/article/details/53116744
- 两种效果相同, 选择其一即可!
- 刚刚粗劣的看了看源码, 没看太明白, @ServletComponentScan 扫描包下注解类, 将Filter直接通过BeanDefined 注册到BeanDefinitionRegistry中, 而代码注册是直接实例化Filter 放到FilterRegistrationBean , 但最终效果相同, 还没理解…
- 网上的各位老猿, 请多赐教! 祝大家前程似锦!