Spring特殊处理机制(持续完善中)

一、事件监听机制

  • ApplicationEvent+@EventListener 基于观察者模式 实现自定义监听器
    • 自定义事件 SysLogEvent继承 ApplicationEvent
    • 两种方式
      • 定义事件监听器 实现 ApplicationListener
      • 在监听方法添加@EventListener(SysLogEvent.class)
      • 定义事件监听基类(为了多类型事件,可以做统一监听,监听基类事件即可)
      • 定义事件监听子类
      • 发布事件 测试
  • WebServerInitializedEvent:tomcat启动后,springboot会发布此事件
package com.grea.qz.event;

import org.springframework.context.ApplicationEvent;


/**
 * @program: qz
 * @description: 公用事件源
 * @author: zzx
 * @create: 
 */

public class BaseEvent<E, S> extends ApplicationEvent {

    protected E event;

    protected S service;

    public BaseEvent(Object source, E event, S service) {
        super(source);
        this.event = event;
        this.service = service;
    }

    public void handleEvent(){}

    public E getEvent() {
        return event;
    }

    public void setEvent(E event) {
        this.event = event;
    }

    public S getService() {
        return service;
    }

    public void setService(S service) {
        this.service = service;
    }

}

package com.grea.qz.listener;

import com.grea.qz.event.BaseEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * @program: edu
 * @description: 事件监听器
 * @author: zzx
 * @create: 
 */
@Component
public class EventListener implements ApplicationListener<BaseEvent> {

    /**
     * 监听BaseEvent事件
     * @param baseEvent
     */
    @Async
    @Override
    public void onApplicationEvent(BaseEvent baseEvent) {
        System.out.println("事件触发!处理自己的业务逻辑");
        baseEvent.handleEvent();  //可以是继承baseEvent 并复写handleEvent方法实现自定义逻辑
    }
}

package com.grea.qz.event;

import com.grea.qz.enums.OrderStatus;
import com.grea.qz.model.modules.OrderRecord;
import com.grea.qz.model.modules.User;
import com.grea.qz.service.OrderRecordService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;

/**
 * 订单操作记录监听
 */
public class OrderRecordEvent extends BaseEvent<OrderStatus,OrderRecordService> {

    private final static Logger logger = LoggerFactory.getLogger(OrderRecordEvent.class);
    protected Integer orderId;
    protected String remarks;
    protected User user;
/*    *//**
     * 订单类型
     * 1数据订单
     * 2画像订单
     * 3固定画像
     *//*
    protected Integer type;*/

    /**
     *
     * @param source
     * @param event
     * @param service
     * @param orderId 订单id
     * @param remarks 备注
     * @param user 操作人
     * @param user 订单类型
     */
    public OrderRecordEvent(Object source, OrderStatus event, OrderRecordService service, Integer orderId, String remarks, User user) {
        super(source, event, service);
        this.orderId = orderId;
        this.remarks = remarks;
        this.user = user;
    }

    @Override
    public void handleEvent() {
        OrderRecord record = new OrderRecord();
        record.setCreateBy(user.getId());
        record.setUserName(user.getUsername());
        record.setCreateTime(new Date());
        record.setOrderId(orderId);
        record.setOperationType(event.getValue());
        record.setRemarks(remarks);
        service.add(record);
    }

    public Integer getOrderId() {
        return orderId;
    }

    public void setOrderId(Integer orderId) {
        this.orderId = orderId;
    }

    public String getRemarks() {
        return remarks;
    }

    public void setRemarks(String remarks) {
        this.remarks = remarks;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

二、属性编辑器

  • 处理请求映射到方法之间的数据处理,通常放在控制层的基类。用于处理所有的请求参数
    • @InitBinder注册编辑器(在控制层基类注册,所有的接口调用都会进行参数处理)
    • 创建自定义编辑器(DateEditor等)
    • 也可以绑定spring提供的默认的编辑器
package com.grea.qz.config.json;

import org.springframework.util.StringUtils;

import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

/**
 * @program: edu
 * @description: 处理日期格式的文本内容、
 *  1、可单独做工具处理
 *  2、可以配合编辑器做全局自动参数处理
 * @author: zzx
 * @create:
 */
public class DateEditor extends PropertyEditorSupport {

    private final static ArrayList<SimpleDateFormat> dateFormats = new ArrayList<>(4);
    static {
        dateFormats.add(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        dateFormats.add(new SimpleDateFormat("yyyy-MM-dd HH:mm"));
        dateFormats.add(new SimpleDateFormat("yyyy-MM-dd"));
        dateFormats.add(new SimpleDateFormat("HH:mm:ss"));
    }

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        if (StringUtils.isEmpty(text)) {
            setValue(null);
        } else {
            for (SimpleDateFormat dateFormat : dateFormats) {
                try {
                    setValue(dateFormat.parse(text));
                    break;
                } catch (ParseException e) {
                    continue;
                }
            }
        }
    }

    @Override
    public String getAsText() {
        Date value = (Date) getValue();
        return (value != null ? dateFormats.get(0).format(value) : "");
    }
}

在这里插入图片描述

三、异常处理机制

  • @ControllerAdvice、@ExceptionHandler 与 ErrorController类
  • 单独使用 @ExceptionHandler(单独使用 只能放在控制层或者控制层基类)
    • 只能处理控制器抛出的异常。也就是进入接口后发生的异常(此方式可以配合ErrorController共同使用)
  • @ControllerAdvice+ @ExceptionHandler
    • 定义在控制层或者控制层基类
      • 拦截所有异常包括未进入控制器的,并且不会走ErrorController的异常拦截
    • 定义单独的拦截类会拦截所有的请求
      • 但会走ErrorController的异常拦截(异常会被ErrorController重新处理);不推荐此用法
  • 实现ErrorController,自定义错误处理异常
    • 可以处理未进入控制器(未进接口的异常,类似404等)和进入控制器的
    • 如果存在@ExceptionHandler(单独使用或者在控制层的),则只会处理未进入控制器
package com.grea.qz.common;

import com.grea.qz.base.vo.RestBody;
import com.grea.qz.exception.ErrorCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.ServletWebRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * @program: edu
 * @description: 替换springboot 默认的BasicErrorController重新定向错误页面
 * @author: zzx
 * @create: 
 */
@RestController
public class CustomErrorController extends BaseController implements ErrorController {

    private static Logger logger = LoggerFactory.getLogger(CustomErrorController.class);

    @Value("${error.path:/error}")
    private String errorPath;

    @Override
    public String getErrorPath() {
        return errorPath;
    }


    /**
     * 自定义返回信息
     * @param request
     * @return
     */
    @RequestMapping(value = "${server.error.path:${error.path:/error}}")
    public RestBody handleError(HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> attributes = getErrorAttributes(request);
        int code = (int) attributes.get("status");
        String message = (String) attributes.get("message");
        if (code < ErrorCode.SERVER_OK.getCode()) {
            message = (String) attributes.get("error");
        }
        logger.error("error :{}--{}", code, message);
        return failure(code, message);
    }


    /**
     * 获取错误信息
     *
     * @param request
     * @return
     */
    private Map<String, Object> getErrorAttributes(HttpServletRequest request) {
        ServletWebRequest servletWebRequest = new ServletWebRequest(request);
        ErrorAttributes errorAttributes = new DefaultErrorAttributes();
        return errorAttributes.getErrorAttributes(servletWebRequest, false);
    }
}

四、事务机制

  • 默认情况下,非public的方法会造成事务失效
    • 在AbstractFallbackTransactionAttributeSource类中,spring隔离了public方法
      • allowPublicMethodsOnly方法,被赋值未true,因此,可以修改allowPublicMethodsOnly的变量为false即可
    • // Don’t allow no-public methods as required.
      if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
      return null;
      }
  • 事务中的异常机制
    • 默认的Spring事务,只会回滚RunTimeException异常
    • @Transactional(isolation = Isolation.READ_UNCOMMITTED, rollbackFor = Exception.class)
      • 设置rollbackFor 确定需要回滚的异常类型
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值