aop+springboot实现数据字典表

概要

spingboot+aop实现数据字典方式

例如:

我们在想数据库中存储文字的时候,效率不高,这个时候我们会考虑存储,code编码格式数据,然后利用aop返回给前端的时候翻译code编码将值给code编码

整体架构流程

我们会新建三张表

1.第一张表是aop_student学生表存储学生等级,兴趣,爱好,我们这里分别存储是code编码并不是存储真实的数据方式,我们会将真实的数据存储到aop_item
2.第二张表是aop_item这张表存储我们真实的数据信息,我们通过code和属性名称查询对应的值

在这里插入图片描述

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for aop_dict
-- ----------------------------
DROP TABLE IF EXISTS `aop_dict`;
CREATE TABLE `aop_dict`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `aop_datasource` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '科目',
  `aop_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '描述',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of aop_dict
-- ----------------------------
INSERT INTO `aop_dict` VALUES (1, 'aop_level', '数学');
INSERT INTO `aop_dict` VALUES (2, 'aop_english', '语文');
INSERT INTO `aop_dict` VALUES (3, 'aop_hobby', '兴趣');

SET FOREIGN_KEY_CHECKS = 1;


SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for aop_item
-- ----------------------------
DROP TABLE IF EXISTS `aop_item`;
CREATE TABLE `aop_item`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `aop_datasource` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `aop_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `aop_val` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of aop_item
-- ----------------------------
INSERT INTO `aop_item` VALUES (1, 'aop_english', '1', '优秀');
INSERT INTO `aop_item` VALUES (2, 'aop_level', '1', '优秀');
INSERT INTO `aop_item` VALUES (3, 'aop_level', '2', '良好');
INSERT INTO `aop_item` VALUES (4, 'aop_english', '2', '良好');
INSERT INTO `aop_item` VALUES (5, 'aop_hobby', '1', 'A');
INSERT INTO `aop_item` VALUES (6, 'aop_hobby', '2', 'B');
INSERT INTO `aop_item` VALUES (7, 'aop_hobby', '3', 'C');
INSERT INTO `aop_item` VALUES (8, 'aop_hobby', '4', 'D');
INSERT INTO `aop_item` VALUES (9, 'aop_hobby', '5', 'E');
INSERT INTO `aop_item` VALUES (10, 'aop_hobby', '6', 'G');

SET FOREIGN_KEY_CHECKS = 1;

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for aop_student
-- ----------------------------
DROP TABLE IF EXISTS `aop_student`;
CREATE TABLE `aop_student`  (
  `id` int(11) NOT NULL,
  `aop_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '姓名',
  `aop_enlish` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '英语',
  `aop_level` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '等级',
  `aop_hobby` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '爱好',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of aop_student
-- ----------------------------
INSERT INTO `aop_student` VALUES (1, '天天', '1', '1', '1,2,3');
INSERT INTO `aop_student` VALUES (2, '拜拜', '2', '2', '4,5');

SET FOREIGN_KEY_CHECKS = 1;

例如:
在语言模型中,编码器和解码器都是由一个个的 Transformer 组件拼接在一起形成的。

目录结构方式

在这里插入图片描述

pom文件信息

   <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.7.7</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.7.7</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.7.7</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.31</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>2.0.22</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <version>2.7.7</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
    </dependencies>

application.yml文件信息

server:
  port: 10001
spring:
  datasource:
    url: jdbc:mysql://192.168.47.128:3306/mycnblog?characterEncoding=utf8&useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
  #redis连接信息
  redis:
    port: 6379
    host: 192.168.47.128
mybatis:
  mapper-locations: classpath:/mapper/*Dao.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

aop实现方式(重点方式)

我们这里主要的实现了,就是在前段请求数据的时候,我们利用aop,拦截数据,将code编码进行翻译,翻译的方式就是我们将code值,获取重新在数据库中查询到的值,存储到code,重新返回给前段展示

package com.cn.aop;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.cn.common.Result;
import com.cn.log.DictRedis;
import com.cn.service.AopItemService;
import com.cn.utils.BeanUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.junit.platform.commons.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;


@Aspect
@Component
public class DictAspect {

    private Logger log = LoggerFactory.getLogger(DictAspect.class);


    @Autowired
    private AopItemService aopItemService;

    @Pointcut("execution(* com.cn.controller.*.*(..))")
    public void execute(){

    }

    @Around("execute()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        Object result = point.proceed();
        stopWatch.stop();
        log.info("获取数据时间:{}",result);
        stopWatch.start();
        translateDict(result);
        stopWatch.stop();
        log.info("翻译字典时间:{}",stopWatch.getLastTaskTimeMillis());
        return result;
    }

    /**
     * 翻译字典
     * @param result
     */
    private void translateDict(Object result) {
        if (result instanceof Result){
        	//封装返回的值
            List<JSONObject> items = new ArrayList<>();
			//将获取对象强制转化成Result对象
            Result dictResult = (Result)result;
			//获取的Result获取getData()转化成list
            List<?> list = (List<?>)dictResult.getData();
			//循环list获取里面注册标注的数据添加值
            for (Object o : list) {
            	//获取值进行json格式的转化
                ObjectMapper mapper = new ObjectMapper();

                String json = "{}";

                try {
                    json=mapper.writeValueAsString(o);
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }

                JSONObject parseObject = JSON.parseObject(json);
				
				//遍历获取对象中的属性和名称
                for (Field field : BeanUtil.getAllFields(o)) {
                	//获取注解标注的值
                    if (field.getAnnotation(DictRedis.class)!=null){
                        String dictDataSource = field.getAnnotation(DictRedis.class).dictDataSource();
                        String dictText = field.getAnnotation(DictRedis.class).dictText();
                        //获取当前key值
                        String keys = String.valueOf(parseObject.get(field.getName()));
                        //获取当前字典中的值
                        String textValue = translateTextValue(dictDataSource,keys);
                        if (StringUtils.isNotBlank(dictText)){
                            parseObject.put(dictText,textValue);
                        }else {
                            parseObject.put(field.getName()+"cc",textValue);
                        }
                    }
                }
                items.add(parseObject);
            }
            dictResult.setData(items);
        }
    }

    /**
     * 获取字典中的值
     * @param dictDataSource 名称
     * @param keys 值
     * @return
     */
    private String translateTextValue(String dictDataSource, String keys) {
        if (StringUtils.isBlank(dictDataSource) || StringUtils.isBlank(keys)){
            return null;
        }
        StringBuffer buffer = new StringBuffer();
		
		//分割key将分割的key循环便利进行查询
        String[] key = keys.split(",");
        for (String k : key) {
            String tempValue =null;
            if (k.trim().length()==0){
                continue;
            }
            log.info("字典中的值:{}",k);
            tempValue = aopItemService.selectByDatasourceKey(dictDataSource,k);

            if (StringUtils.isNotBlank(tempValue)){
                if (!"".equals(buffer.toString())){
                    buffer.append(",");
                }
                buffer.append(tempValue);
            }
        }
        return buffer.toString();
    }


}


注解

我们注释在需要翻译的实体类上 这个字段必须是经过在aop_item表中的字段我们通过code和datasource数据方式来确定这个val值
package com.cn.log;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

    /**
     * 方法描述:类型dataSource
     * @return
     */
    String dictDataSource();

    /**
     * 返回后台的put到json中的文件key值
     * @return
     */
    String dictText() default "";

}

package com.cn.log;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DoDict {
}

工具类

获取所有属性中的名称

package com.cn.utils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class BeanUtil {
    /**
     * 通过反射包括父类的所有属性类型
     * @param object
     * @return
     */
    public static Field[] getAllFields(Object object){
        Class<?> clazz = object.getClass();
        List<Field> fieldList = new ArrayList<>();
        while (clazz!=null){
            fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            clazz = clazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        return fields;

    }
}

实体类文件信息

package com.cn.entity;


import com.cn.log.DictRedis;

import java.io.Serializable;

/**
 * (AopStudent)实体类
 *
 * @author makejava
 * @since 2023-05-24 18:35:57
 */
public class AopStudent implements Serializable {
    private static final long serialVersionUID = 127399537035303507L;
    
    private Integer id;
    /**
    * 姓名
    */
    private String aopName;
    /**
    * 英语
    */
    @DictRedis(dictDataSource = "aop_english",dictText = "aop-cc")
    private String aopEnlish;
    /**
    * 等级
    */
    @DictRedis(dictDataSource = "aop_level")
    private String aopLevel;
    /**
    * 爱好
    */
    @DictRedis(dictDataSource = "aop_hobby")
    private String aopHobby;


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getAopName() {
        return aopName;
    }

    public void setAopName(String aopName) {
        this.aopName = aopName;
    }

    public String getAopEnlish() {
        return aopEnlish;
    }

    public void setAopEnlish(String aopEnlish) {
        this.aopEnlish = aopEnlish;
    }

    public String getAopLevel() {
        return aopLevel;
    }

    public void setAopLevel(String aopLevel) {
        this.aopLevel = aopLevel;
    }

    public String getAopHobby() {
        return aopHobby;
    }

    public void setAopHobby(String aopHobby) {
        this.aopHobby = aopHobby;
    }

}

controller信息

package com.cn.controller;

import com.cn.common.Constant;
import com.cn.common.Result;
import com.cn.entity.AopStudent;
import com.cn.log.DoDict;
import com.cn.service.AopStudentService;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

/**
 * (AopStudent)表控制层
 *
 * @author makejava
 * @since 2023-05-24 18:35:59
 */
@RestController
@RequestMapping("aopStudent")
public class AopStudentController {
    /**
     * 服务对象
     */
    @Resource
    private AopStudentService aopStudentService;

    /**
     * 通过主键查询单条数据
     *
     * @param id 主键
     * @return 单条数据
     */
    @GetMapping("selectOne")
    public AopStudent selectOne(Integer id) {
        return this.aopStudentService.queryById(id);
    }

    /**
     * 获取所有学生的信息
     * @return 返回所有学生信息
     */
    @DoDict
    @GetMapping("findAll")
    public Result findAll(){
        List<AopStudent> all =aopStudentService.findAll();
        return new Result(Constant.success,"成功获取信息",all);
    }

}

测试

访问地址信息
http://localhost:10001/aopStudent/findAll
在这里插入图片描述

小结

这里我们查询效率更高,主要的方式通过分表的方式和aop注解方式进行提升效率方式

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以使用 RedisTemplate 实现分布式锁,具体实现步骤如下: 1. 定义一个自定义注解,用于标识需要加锁的方法。 2. 在方法执行前获取锁,执行后释放锁。 3. 使用 RedisTemplate 操作 Redis,实现分布式锁。 下面是示例代码: ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface DistributedLock { String key(); long expire() default 30000; } @Component @Aspect public class DistributedLockAspect { @Autowired private RedisTemplate<String, String> redisTemplate; @Around("@annotation(distributedLock)") public Object doAround(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable { String key = distributedLock.key(); long expire = distributedLock.expire(); // 获取锁 boolean locked = false; String lockKey = "lock:" + key; String lockValue = UUID.randomUUID().toString(); try { locked = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, expire, TimeUnit.MILLISECONDS); if (!locked) { throw new RuntimeException("获取锁失败"); } // 执行方法 return joinPoint.proceed(); } finally { // 释放锁 if (locked) { String value = redisTemplate.opsForValue().get(lockKey); if (lockValue.equals(value)) { redisTemplate.delete(lockKey); } } } } } ``` 在需要加锁的方法上加上 @DistributedLock 注解,指定锁的 key 和过期时间即可。 例如: ```java @Service public class UserService { @Autowired private UserDao userDao; @DistributedLock(key = "user:update:${#userId}") public void updateUser(long userId, String name) { userDao.updateUser(userId, name); } } ``` 这样就可以实现分布式锁了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值