代码优化设计(一)

1、通用的结果处理,及错误信息类封装

2、md5前台后台两次加盐加密

3、全局异常处理

4、通用的key生成策略

5、通用的RedisService方法

通用的结果处理,及错误信息类封装

写一个Result类来封装返回结果,避免重复性的代码出现到controller层

package com.javaxl.miaosha_02.result;

public class Result<T> {
    
    private int code;
    private String msg;
    private T data;
    
    /**
     *  成功时候的调用
     * */
    public static  <T> Result<T> success(T data){
        return new Result<T>(data);
    }
    
    /**
     *  失败时候的调用
     * */
    public static  <T> Result<T> error(CodeMsg codeMsg){
        return new Result<T>(codeMsg);
    }
    
    private Result(T data) {
        this.data = data;
    }
    
    private Result(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    
    private Result(CodeMsg codeMsg) {
        if(codeMsg != null) {
            this.code = codeMsg.getCode();
            this.msg = codeMsg.getMsg();
        }
    }
    
    
    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
    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;
    }
}

CodeMsg:对系统常量进行封装

package com.javaxl.miaosha_02.result;

public class CodeMsg {
    
    private int code;
    private String msg;
    
    //通用的错误码
    public static CodeMsg SUCCESS = new CodeMsg(0, "success");
    public static CodeMsg SERVER_ERROR = new CodeMsg(500100, "服务端异常");
    public static CodeMsg BIND_ERROR = new CodeMsg(500101, "参数校验异常:%s");
    //登录模块 5002XX
    public static CodeMsg SESSION_ERROR = new CodeMsg(500210, "Session不存在或者已经失效");
    public static CodeMsg PASSWORD_EMPTY = new CodeMsg(500211, "登录密码不能为空");
    public static CodeMsg MOBILE_EMPTY = new CodeMsg(500212, "手机号不能为空");
    public static CodeMsg MOBILE_ERROR = new CodeMsg(500213, "手机号格式错误");
    public static CodeMsg MOBILE_NOT_EXIST = new CodeMsg(500214, "手机号不存在");
    public static CodeMsg PASSWORD_ERROR = new CodeMsg(500215, "密码错误");
    
    
    //商品模块 5003XX
    
    
    //订单模块 5004XX
    public static CodeMsg ORDER_NOT_EXIST = new CodeMsg(500400, "订单不存在");
    
    //秒杀模块 5005XX
    public static CodeMsg MIAO_SHA_OVER = new CodeMsg(500500, "商品已经秒杀完毕");
    public static CodeMsg REPEATE_MIAOSHA = new CodeMsg(500501, "不能重复秒杀");
    
    
    private CodeMsg( ) {
    }
            
    private CodeMsg( int code,String msg ) {
        this.code = code;
        this.msg = msg;
    }
    
    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    
    public CodeMsg fillArgs(Object... args) {
        int code = this.code;
        String message = String.format(this.msg, args);
        return new CodeMsg(code, message);
    }

    @Override
    public String toString() {
        return "CodeMsg [code=" + code + ", msg=" + msg + "]";
    }
    
    
}

md5前台后台两次加盐加密
一次:客户端密码加密,防止明文密码被劫持

二次:服务端shiro再加密一次

前台加密js代码:

function doLogin(){
    g_showLoading();
    
    var inputPass = $("#password").val();
    var salt = g_passsword_salt;
    var str = ""+salt.charAt(0)+salt.charAt(2) + inputPass +salt.charAt(5) + salt.charAt(4);
    var password = md5(str);
    
    $.ajax({
        url: "/login/do_login",
        type: "POST",
        data:{
            mobile:$("#mobile").val(),
            password: password
        },
        success:function(data){
            layer.closeAll();
            if(data.code == 0){
                layer.msg("成功");
                window.location.href="/goods/to_list";
            }else{
                layer.msg(data.msg);
            }
        },
        error:function(){
            layer.closeAll();
        }
    });
}

后台MiaoshaUserService : 

package com.javaxl.miaosha_02.service;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;

import com.javaxl.miaosha_02.dao.MiaoshaUserDao;
import com.javaxl.miaosha_02.domain.MiaoshaUser;
import com.javaxl.miaosha_02.exception.GlobalException;
import com.javaxl.miaosha_02.redis.MiaoshaUserKey;
import com.javaxl.miaosha_02.redis.RedisService;
import com.javaxl.miaosha_02.result.CodeMsg;
import com.javaxl.miaosha_02.shiro.PasswordHelper;
import com.javaxl.miaosha_02.util.MD5Util;
import com.javaxl.miaosha_02.util.UUIDUtil;
import com.javaxl.miaosha_02.vo.LoginVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


@Service
public class MiaoshaUserService {
    
    
    public static final String COOKI_NAME_TOKEN = "token";
    
    @Autowired
    MiaoshaUserDao miaoshaUserDao;
    
    @Autowired
    RedisService redisService;
    
    public MiaoshaUser getById(long id) {
        //取缓存
        MiaoshaUser user = redisService.get(MiaoshaUserKey.getById, ""+id, MiaoshaUser.class);
        if(user != null) {
            return user;
        }
        //取数据库
        user = miaoshaUserDao.getById(id);
        if(user != null) {
            redisService.set(MiaoshaUserKey.getById, ""+id, user);
        }
        return user;
    }
    // http://blog.csdn.net/tTU1EvLDeLFq5btqiK/article/details/78693323
    public boolean updatePassword(String token, long id, String formPass) {
        //取user
        MiaoshaUser user = getById(id);
        if(user == null) {
            throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
        }
        //更新数据库
        MiaoshaUser toBeUpdate = new MiaoshaUser();
        toBeUpdate.setId(id);
        toBeUpdate.setPassword(MD5Util.formPassToDBPass(formPass, user.getSalt()));
        miaoshaUserDao.update(toBeUpdate);
        //处理缓存
        redisService.delete(MiaoshaUserKey.getById, ""+id);
        user.setPassword(toBeUpdate.getPassword());
        redisService.set(MiaoshaUserKey.token, token, user);
        return true;
    }


    public MiaoshaUser getByToken(HttpServletResponse response, String token) {
        if(StringUtils.isEmpty(token)) {
            return null;
        }
        MiaoshaUser user = redisService.get(MiaoshaUserKey.token, token, MiaoshaUser.class);
        //延长有效期
        if(user != null) {
            addCookie(response, token, user);
        }
        return user;
    }
    

    public String login(HttpServletResponse response, LoginVo loginVo) {
        if(loginVo == null) {
            throw new GlobalException(CodeMsg.SERVER_ERROR);
        }
        String mobile = loginVo.getMobile();
        String formPass = loginVo.getPassword();
        //判断手机号是否存在
        MiaoshaUser user = getById(Long.parseLong(mobile));
        if(user == null) {
            throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
        }
        //验证密码
        String dbPass = user.getPassword();
        String saltDB = user.getSalt();
        if(!PasswordHelper.checkCredentials(formPass, saltDB, dbPass)) {
            throw new GlobalException(CodeMsg.PASSWORD_ERROR);
        }
        //生成cookie
        String token     = UUIDUtil.uuid();
        addCookie(response, token, user);
        return token;
    }
    
    private void addCookie(HttpServletResponse response, String token, MiaoshaUser user) {
        redisService.set(MiaoshaUserKey.token, token, user);
        Cookie cookie = new Cookie(COOKI_NAME_TOKEN, token);
        cookie.setMaxAge(MiaoshaUserKey.token.expireSeconds());
        cookie.setPath("/");
        response.addCookie(cookie);
    }

}


全局异常处理

如果系统发生了异常,不做统一异常处理,前端会给用户展示一大片看不懂的文字。做统一异常处理后当异常发生后可以给用户一个温馨的提示,不至于使用户满头雾水,所以一方面是为了更好的用户体验 如果不统一全局异常,服务端和前端在遇到异常的时候处理起来杂乱无章非常费力。所以另一方面是为了制定规范提高工作效率
我们都知道使用 try-catch 可以捕捉异常,可以 throws 抛出异常。那么在 Spring Boot 中我们如何处理异常,如何处理得更加优雅呢


自定义异常类:

package com.javaxl.miaosha_02.exception;


import com.javaxl.miaosha_02.result.CodeMsg;

public class GlobalException extends RuntimeException{

    private static final long serialVersionUID = 1L;
    
    private CodeMsg cm;
    
    public GlobalException(CodeMsg cm) {
        super(cm.toString());
        this.cm = cm;
    }

    public CodeMsg getCm() {
        return cm;
    }

}

全局异常处理类

package com.javaxl.miaosha_02.exception;

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import com.javaxl.miaosha_02.result.CodeMsg;
import com.javaxl.miaosha_02.result.Result;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;


@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
    @ExceptionHandler(value=Exception.class)
    public Result<String> exceptionHandler(HttpServletRequest request, Exception e){
        e.printStackTrace();
        if(e instanceof GlobalException) {
            GlobalException ex = (GlobalException)e;
            return Result.error(ex.getCm());
        }else if(e instanceof BindException) {
            BindException ex = (BindException)e;
            List<ObjectError> errors = ex.getAllErrors();
            ObjectError error = errors.get(0);
            String msg = error.getDefaultMessage();
            return Result.error(CodeMsg.BIND_ERROR.fillArgs(msg));
        }else {
            return Result.error(CodeMsg.SERVER_ERROR);
        }
    }
}

通用的key生成策略

KeyPrefix
package com.javaxl.miaosha_02.redis;

public interface KeyPrefix {


    public int expireSeconds();//过期时间设置
    
    public String getPrefix();//前缀
    
}
BasePrefix :
package com.javaxl.miaosha_02.redis;

public abstract class BasePrefix implements KeyPrefix{
    
    private int expireSeconds;
    
    private String prefix;
    
    public BasePrefix(String prefix) {//0代表永不过期
        this(0, prefix);
    }
    
    public BasePrefix( int expireSeconds, String prefix) {
        this.expireSeconds = expireSeconds;
        this.prefix = prefix;
    }
    
    public int expireSeconds() {//默认0代表永不过期
        return expireSeconds;
    }

    public String getPrefix() {
        String className = getClass().getSimpleName();
        return className+":" + prefix;
    }

}

以MiaoshaUserKey为例
package com.javaxl.miaosha_02.redis;

public class MiaoshaUserKey extends BasePrefix{

    public static final int TOKEN_EXPIRE = 3600*24 * 2;
    private MiaoshaUserKey(int expireSeconds, String prefix) {
        super(expireSeconds, prefix);
    }
    public static MiaoshaUserKey token = new MiaoshaUserKey(TOKEN_EXPIRE, "tk");
    public static MiaoshaUserKey getById = new MiaoshaUserKey(0, "id");
}

通用的RedisService方法

高并发redis做缓存是很通用的手段,避免出现重复的redis操作方法

搞个通用的存值、取值、自增、自减...的方法

package com.javaxl.miaosha_02.redis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

@Service
public class RedisService {
    
    @Autowired
    JedisPool jedisPool;
    
    /**
     * 获取当个对象
     * */
    public <T> T get(KeyPrefix prefix, String key,  Class<T> clazz) {
         Jedis jedis = null;
         try {
             jedis =  jedisPool.getResource();
             //生成真正的key
             String realKey  = prefix.getPrefix() + key;
             String  str = jedis.get(realKey);
             T t =  stringToBean(str, clazz);
             return t;
         }finally {
              returnToPool(jedis);
         }
    }
    
    /**
     * 设置对象
     * */
    public <T> boolean set(KeyPrefix prefix, String key,  T value) {
         Jedis jedis = null;
         try {
             jedis =  jedisPool.getResource();
             String str = beanToString(value);
             if(str == null || str.length() <= 0) {
                 return false;
             }
            //生成真正的key
             String realKey  = prefix.getPrefix() + key;
             int seconds =  prefix.expireSeconds();
             if(seconds <= 0) {
                 jedis.set(realKey, str);
             }else {
                 jedis.setex(realKey, seconds, str);
             }
             return true;
         }finally {
              returnToPool(jedis);
         }
    }
    
    /**
     * 判断key是否存在
     * */
    public <T> boolean exists(KeyPrefix prefix, String key) {
         Jedis jedis = null;
         try {
             jedis =  jedisPool.getResource();
            //生成真正的key
             String realKey  = prefix.getPrefix() + key;
            return  jedis.exists(realKey);
         }finally {
              returnToPool(jedis);
         }
    }
    
    /**
     * 删除
     * */
    public boolean delete(KeyPrefix prefix, String key) {
         Jedis jedis = null;
         try {
             jedis =  jedisPool.getResource();
            //生成真正的key
            String realKey  = prefix.getPrefix() + key;
            long ret =  jedis.del(key);
            return ret > 0;
         }finally {
              returnToPool(jedis);
         }
    }
    
    /**
     * 增加值
     * */
    public <T> Long incr(KeyPrefix prefix, String key) {
         Jedis jedis = null;
         try {
             jedis =  jedisPool.getResource();
            //生成真正的key
             String realKey  = prefix.getPrefix() + key;
            return  jedis.incr(realKey);
         }finally {
              returnToPool(jedis);
         }
    }
    
    /**
     * 减少值
     * */
    public <T> Long decr(KeyPrefix prefix, String key) {
         Jedis jedis = null;
         try {
             jedis =  jedisPool.getResource();
            //生成真正的key
             String realKey  = prefix.getPrefix() + key;
            return  jedis.decr(realKey);
         }finally {
              returnToPool(jedis);
         }
    }
    
    private <T> String beanToString(T value) {
        if(value == null) {
            return null;
        }
        Class<?> clazz = value.getClass();
        if(clazz == int.class || clazz == Integer.class) {
             return ""+value;
        }else if(clazz == String.class) {
             return (String)value;
        }else if(clazz == long.class || clazz == Long.class) {
            return ""+value;
        }else {
            return JSON.toJSONString(value);
        }
    }

    @SuppressWarnings("unchecked")
    private <T> T stringToBean(String str, Class<T> clazz) {
        if(str == null || str.length() <= 0 || clazz == null) {
             return null;
        }
        if(clazz == int.class || clazz == Integer.class) {
             return (T)Integer.valueOf(str);
        }else if(clazz == String.class) {
             return (T)str;
        }else if(clazz == long.class || clazz == Long.class) {
            return  (T)Long.valueOf(str);
        }else {
            return JSON.toJavaObject(JSON.parseObject(str), clazz);
        }
    }

    private void returnToPool(Jedis jedis) {
         if(jedis != null) {
             jedis.close();
         }
    }

}
原文地址:https://www.cnblogs.com/psyu/p/12110945.html