java项目经验总结

1.如果对精度要求不高的情况下使用如下方式获得系统时间戳。原理连接

System.out.println(LocalDateTime.now());

2.如果需要获得格式化的时间,或者将字符串转换成日期格式,按如下方式进行书写。原理连接

public class TestMain {
    
    
    public static final DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");

    public static void main(String[] args) {
    
    
        String test=TestMain.dateTimeFormatter.format(LocalDateTime.now());
        System.out.println(test);
    }

3.在线程中可以使用threadlocal放置线程中共享的信息。

public class UserInfoThreadlocal {
    
    
    private static final ThreadLocal<Long> threaslocal = new ThreadLocal<>();
    public static void put(Long userId) {
    
    
        remove();
        threaslocal.set(userId);
    }
    public static Long get() {
    
    
        return threaslocal.get();
    }
    public static void remove() {
    
    
        threaslocal.remove();
    }
}

这是本人在项目中使用的方式,在对jwt进行权限验证通过以后会将一些线程共享的信息放入ThreadLocal中,springsecurity实际上使用的也是threadlocal进行权限验证。

4.为了让事务机制起作用,当service调用service方法的时候选择创建新的service,例如AService非事务方法需要调用事务方法,则创建一个Bservice,然后将BService注入到AService中。

5.数据库中的小数使用Decimal,mysql中的Decimal采用的是字符串存贮的方式,在java中使用BigDecimal进行运算,BigDecimal底层使用BigInt存储数据,BigInt使用int[]数组来存储数据。

6.可以使用枚举类定义常量。

public enum TransStatusEnum {
    
    
    SUCCSEE(10, "交易成功"),

    LOADING(20, "交易中"),

    FAIL(30, "交易失败"),

    CancelOrder(40,"撤单"),

    OrderFinish(50, "售卖结束");

    private Integer status;
    private String desc;

    private TransStatusEnum(Integer status, String desc) {
    
    
        this.status = status;
        this.desc = desc;
    }
    
    public static TransStatusEnum getEnumByStatus(Integer code) {
    
    
        for (TransStatusEnum temp : TransStatusEnum.values()) {
    
    
            if (code == temp.getStatus()) {
    
    
                return temp;
            }
        }
        return TransStatusEnum.LOADING;
    }

    public Integer getStatus() {
    
    
        return status;
    }

    public void setStatus(Integer status) {
    
    
        this.status = status;
    }

    public  String getDesc() {
    
    
        return desc;
    }

    public void setDesc(String desc) {
    
    
        this.desc = desc;
    }

    public static String getDesc(Integer i){
    
    
        return getEnumByStatus(i).getDesc();
    }
}

7.使用拦截器和注解结合的方式来完成业务。

/**
 * 不校验token
 * @see
 */
@Documented
@Inherited
@Target({
    
    ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NoVerificationToken {
    
    

}
@Component
@Slf4j
public class TokenInterceptor extends HandlerInterceptorAdapter {
    
    
    @Autowired
    private TokenService tokenService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    
    

        // 获取方法上的注解
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();

        PenguinLogThreadLocal.remove();

        if (method.isAnnotationPresent(NoVerificationToken.class)) {
    
    
            return true;
        }

8.使用一次性token来防止接口的幂等性

@PostMapping("/repeatLimNo")
    @ApiOperation(value = "获取请求序列", notes = "获取请求序列--拦截重复请求")
    public Outcome<String> getToken(@RequestHeader(value = "token") String token, HttpServletRequest request) {
    
    
        return Outcome.success("", repeatLimiterSeq.generateSeq());
    }

该接口返回一个唯一的请求序列放在redis中,请求一次失效,在需要防止接口幂等性的接口上传送,且该字段为必传字段。

    @Override
    public String generateSeq() {
    
    
        //使用UUID生成 token
        String token = UUID.randomUUID().toString();
        token=token.replaceAll("-","");
        //存入Redis,key:token,过期时间10分钟
        redisUtil.set("repeatLimNo::"+token,token,20*60);
        PenguinLogThreadLocal.setParam(token);
        return token;
    }

猜你喜欢

转载自blog.csdn.net/a1773570500/article/details/125637895