【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