【SpringBoot+Mybatis-plus+maven+session拦截器+配置字典项自定义注解】实现简单的用户登录与字段字典项翻译(附源码)

【SpringBoot+Mybatis-plus+maven+session拦截器+配置字典项自定义注解@Dict】实现简单的用户登录与字段字典项翻译(附源码)


前言

本文主要给下一章人脸识别登录做铺垫,大致讲解一下用户登录获取sission并使用;并且对字典项自定义注解@Dict环绕通知获取需要翻译的字段自动翻译,一劳永逸。
前期准备:

1.用户表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user`  (
  `user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户id',
  `username` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
  `password` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',
  `sex` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '性别',
  `orgin_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '组织机构id',
  `orgin_code` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '组织机构代码',
  `yxbz` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '有效标识 1. 有效;2. 失效',
  `create_by` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `update_time` timestamp NULL DEFAULT NULL COMMENT '修改时间',
  PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

SET FOREIGN_KEY_CHECKS = 1;

2.字典表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_dict
-- ----------------------------
DROP TABLE IF EXISTS `t_dict`;
CREATE TABLE `t_dict`  (
  `dic_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典id',
  `dic_code` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '字典项',
  `dic_value` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '字典代码',
  `dic_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '字典名称',
  `yxbz` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '有效标识 1. 有效 0. 失效',
  `create_by` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_by` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新人',
  `update_time` timestamp NULL DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`dic_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

SET FOREIGN_KEY_CHECKS = 1;

3.学生表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_student
-- ----------------------------
DROP TABLE IF EXISTS `t_student`;
CREATE TABLE `t_student`  (
  `sid` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'id',
  `sname` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '姓名',
  `sage` int(3) NULL DEFAULT NULL COMMENT '年龄',
  `ssex` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '性别',
  `sphone` char(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号码',
  `yxbz` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '有效标识 1. 有效 0. 失效',
  `create_by` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建日期',
  `update_by` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '修改人',
  `update_time` timestamp NULL DEFAULT NULL COMMENT '修改时间',
  PRIMARY KEY (`sid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

SET FOREIGN_KEY_CHECKS = 1;

一、用户登录

本章博主使用传统session登录方式,后续有时间尝试一下token或者Jwt登录,有兴趣的同学也可以尝试一下,关于此三种的登录方式优缺点点击

1.session拦截器

作用:预处理,拦截访问接口,处理接口session中是否携带用户信息,有:访问通过;否则访问不通过,直接退出,要求用户登录。

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.info("=============开始请求地址拦截=============");
        HttpSession session = request.getSession(false);

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        String name = method.getName();
        logger.info("=============拦截到了方法: {}, 在该方法执行前执行=============", name);

        if (session != null && session.getAttribute("currntUser") != null) {
            return true;
        } else {
            PrintWriter printWriter = response.getWriter();
            printWriter.write("{code:1,message:\"log out!Please log in!\"}");
            logger.info("=============登录失效,请重新登录!=============");
            return false;
        }
    }

2.自定义拦截器

作用:配置拦截器,拦截除登录、注册之外的接口。

@Override
public void addInterceptors(InterceptorRegistry registry) {
    // 设置拦截的路径、不拦截的路径、优先级等等
    // 配置除用户登录和用户注册拦截器
    registry.addInterceptor(new SessionInterceptor()).addPathPatterns("/**").excludePathPatterns("/admission/tuser/login/**", "/face/identification/face/register/**");
}

3.用户登录controller层

作用:session内插入用户信息和失效期。

    /**
     * 登录
     */
    @GetMapping("/login/do")
    public R login(@Validated String username, @Validated String password, HttpServletRequest request){
        R r = tUserService.login(username, password);

        if (!r.get("code").equals("1")) {

            request.getSession().setAttribute("currntUser", r.get("user"));
            // 配置session失效时间
            request.getSession().setMaxInactiveInterval(30*60);
        }
        return r;
    }

4.用户登录service层

作用:获取用户登录信息检测用户表,并对用户信息保密处置。

@Override
public R login(String username, String password) {

    int resultCount = userDao.queryCount(username);
    if (0 == resultCount) {
        return R.error(1, "用户不存在!");
    }

    TUserEntity tUserEntity = userDao.queryUserLogin(username, password);
    if (null == tUserEntity) {
        return R.error(1, "密码错误,请重新输入!");
    }
    R r = new R();
    // 把密码设置为空,把User返回给接口使用
    tUserEntity.setPassword(StringUtils.EMPTY);
    r.put("user", tUserEntity);
    return r;
}

二、自定义注解-配置字典项翻译@Dict注解

1.@Dict注解

自定义注解Target参数使用方式:

ElementType.TYPE:接口、类、枚举、注解
ElementType.FIELD:字段、枚举的常量
ElementType.METHOD:方法
ElementType.PARAMETER:方法参数
ElementType.CONSTRUCTOR:构造函数
ElementType.LOCAL_VARIABLE:局部变量
ElementType.ANNOTATION_TYPE:注解
ElementType.PACKAGE:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Dict {

    /**
     * 方法描述:  数据dataSource
     * @return 返回类型: String
     */
    String dicDataSource();

    /**
     * 方法描述:  这是返回后Put到josn中的文本 key 值
     * @return 返回类型: String
     */
    String dicText() default "";
}

2.字典项环绕通知处理

@Aspect
@Component
@Slf4j
public class DictAspect {
    private static String DICT_TEXT_SUFFIX = "Name";

    @Autowired
    private TStudentService studentService;

    // 定义切点Pointcut 拦截所有对服务器的请求
//    @Pointcut("execution( * com.*.*.controller.*.*(..))")
    @Pointcut("execution(* com.example..controller..*(..))")
    public void excudeService() {
    }

    /**
     * 这是触发 excudeService 的时候会执行的,在环绕通知中目标对象方法被调用后的结果进行再处理
     *
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("excudeService()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        //这是定义开始事件
        long time1 = System.currentTimeMillis();
        //这是方法并获取返回结果
        Object result = pjp.proceed();
        //这是获取到 结束时间
        long time2 = System.currentTimeMillis();
        log.debug("获取JSON数据 耗时:" + (time2 - time1) + "ms");
        //解析开始时间
        long start = System.currentTimeMillis();
        //开始解析(翻译字段内部的值凡是打了 @Dict 这玩意的都会被翻译)
        this.parseDictText(result);
        //解析结束时间
        long end = System.currentTimeMillis();
        log.debug("解析注入JSON数据  耗时" + (end - start) + "ms");
        return result;
    }

    /**
     * 本方法针对返回对象为Result 的PageUtils的分页列表数据进行动态字典注入
     * @param result
     */
    private void parseDictText(Object result) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        if (result instanceof PageUtils) {
            List<JSONObject> items = new ArrayList<>();
            PageUtils pageUtils = (PageUtils) result;
            String jsons = JSON.toJSONString(pageUtils);
            //循环查找出来的数据
            List<TStudentEntity> studentEntity = JSON.parseArray(JSON.parseObject(jsons).getString("list"), TStudentEntity.class);
            for (TStudentEntity tStudentEntity : studentEntity) {
                JSONObject resultJson = new JSONObject(new LinkedHashMap<>());
                for (Field field : ObjConvertUtils.getAllFields(tStudentEntity)) {

                    boolean flag = true;
                    if (field.getAnnotation(Dict.class) != null) {

                        flag = false;

                        String datasource = field.getAnnotation(Dict.class).dicDataSource();
                        String text = field.getAnnotation(Dict.class).dicText();
                        //获取当前带翻译的值
                        // 根据反射名称动态调用Getter
                        String key = (String) tStudentEntity.getClass().getMethod(
                                "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1)).invoke(tStudentEntity);

                        //翻译字典值对应的txt
                        String textValue = DicDataUtils.getDictName(datasource, key);
                        //如果给了文本名
                        if (!StringUtils.isEmpty(text)) {
                            resultJson.put(field.getName(), tStudentEntity.getClass().getMethod(
                                    "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1)).invoke(tStudentEntity));
                        } else {
                            resultJson.put(field.getName(), tStudentEntity.getClass().getMethod(
                                    "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1)).invoke(tStudentEntity));
                            //走默认策略
                            resultJson.put(field.getName() + DICT_TEXT_SUFFIX, textValue);
                        }

                    }
                    if (!field.getName().equals("serialVersionUID") && flag) {
                        resultJson.put(field.getName(), tStudentEntity.getClass().getMethod(
                                "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1)).invoke(tStudentEntity));
                    }
                    //date类型默认转换string格式化日期
                    if (field.getType().getName().equals("java.util.Date") && field.getAnnotation(JsonFormat.class) == null && resultJson.get(field.getName()) != null) {
                        SimpleDateFormat aDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        resultJson.put(field.getName(), aDate.format(resultJson.get(field.getName())));
                    }
                }
                items.add(resultJson);
            }
            pageUtils.setList(items);
        }
    }
}

2.1.获取类所有属性

/**
     * 获取类的所有属性,包括父类
     *
     * @param object
     * @return
     */
    public static Field[] getAllFields(Object object) {
        Class<?> clazz = object.getClass();
        List<Field> fieldList = new ArrayList<>();
        while (clazz != null) {
            Field[] declaredFields = clazz.getDeclaredFields();

            fieldList.addAll(new ArrayList<>(Arrays.asList(declaredFields)));
            clazz = clazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        return fields;
    }

3.Entity层使用@Dict

	/**
	 * 性别
	 */
	@Dict(dicDataSource = DictKey.SEX)
	private String ssex;

4.配置DictKey、t_dict表中的sex数据以及t_student表中的学生数据

4.1.DictKey

public class DictKey {

    /** 性别 */
    public final static String SEX = "common_sex";
}

4.2.t_dict表中的sex数据

在这里插入图片描述

4.3.t_student表中的学生数据

在这里插入图片描述

5.请求结果

带有@Dict注解的sex已经翻译并返回。
在这里插入图片描述


总结

提示:这里的@Dict只做了TStudentEntity单个表的字段翻译,后续有时间再做成通用。

通用@Dict大致思路,根据注解查询出对应的实体,将实体转化成Json,再获取有@Dict的字段做翻译处理,结果添加再Json上输出结果。

项目git地址:https://gitee.com/table-tennis-king/dict-and-export.git

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值