aop+springboot实现数据字典表

news2025/1/10 17:03:16

文章目录

    • 概要
    • 整体架构流程
    • 目录结构方式
      • pom文件信息
      • application.yml文件信息
      • aop实现方式(重点方式)
        • 我们这里主要的实现了,就是在前段请求数据的时候,我们利用aop,拦截数据,将code编码进行翻译,翻译的方式就是我们将code值,获取重新在数据库中查询到的值,存储到code,重新返回给前段展示
      • 注解
        • 我们注释在需要翻译的实体类上 `这个字段必须是经过在aop_item表中的字段`我们通过code和datasource数据方式来确定这个val值
      • 工具类
      • 实体类文件信息
      • controller信息
      • 测试
    • 小结

概要

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注解方式进行提升效率方式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/567712.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LabVIEWCompactRIO 开发指南34 在模拟模式下调试

LabVIEWCompactRIO 开发指南34 在模拟模式下调试 在仿真模式下执行LabVIEW FPGA VI时&#xff0c;可以访问标准LabVIEW调试功能&#xff0c;包括突出显示执行、探测和断点。LabVIEW2013及更高版本包含了一个额外的调试工具&#xff0c;称为采样探针。在仿真中运行时插入FPGA设…

U盘超级加密3000试用版与正式版的区别有哪些?

U盘超级加密3000是一款专业的U盘加密软件&#xff0c;它可以为U盘、移动硬盘、内存卡等移动存储设备加密。软件拥有正式版和试用版&#xff0c;那么这两个版本有什么区别呢&#xff1f;下面我们就一起来了解一下。 U盘超级加密3000试用版和正式版的区别 打开软件时的区别 试用…

C++第三章:字符串、向量和数组

字符串、向量和数组 一、命名空间的using声明每个名字独立using声明头文件不应包含using声明 二、标准库类型string2.1 定义和初始化string对象直接初始化和拷贝初始化 2.2 string对象上的操作读写string对象读取未知数量的string对象使用getline读取一整行string的empty和size…

TypeScript9-声明文件

本篇文章来讲 TypeScript 的声明文件。 当我们在使用第三方库的时候&#xff0c;很多第三方库不是用 TS 写的&#xff0c;它们是通过原生的 JavaScript 或者是浏览器 / 或者是 node 提供的 run time 对象。如果我们直接使用 TS 肯定就会报编译不通过。 1. 声明语句 假设一个…

【学习日记2023.5.24】 之 用户端模块开发 用户端小程序_服务端接入微信认证_完善用户端商品浏览模块

文章目录 6. 用户端模块开发6.1 HttpClient6.1.1 介绍6.1.2 入门案例6.1.2.1 GET方式请求6.1.2.2 POST方式请求 6.2 微信小程序开发6.2.1 介绍6.2.2 准备工作6.2.3 入门案例6.2.3.1 小程序目录结构6.2.3.2 编写和编译小程序6.2.3.3 发布小程序 6.3 微信登录6.3.1 导入小程序代码…

MATLAB 之 绘制三维图形的基本函数、三维曲面和其他三维图形

文章目录 一、绘制三维曲线的基本函数二、三维曲面1. 平面网格坐标矩阵的生成2. 绘制三维曲面的函数3. 标准三维曲面 三、其他三维图形1. 三维条形图2. 三维饼图3. 三维实心图4. 三维散点图5. 三维杆图6. 三维箭头图 三维图形具有更强的数据表现能力&#xff0c;为此 MATLAB 提…

关于CSDN如何获得铁粉

一、发表高质量技术博客 获得铁粉首先是需要有粉丝关注&#xff0c;在CSDN有粉丝关注&#xff0c;就需要多发表写技术文章而且最好是高质量文章&#xff0c;条理清晰&#xff0c;复合当下主流技术&#xff0c;或者新的技术方向&#xff0c;图文并茂的那种。这样通过搜索引擎搜到…

虚拟专用网络-那些年你错过的“VPN 盲点”

我们先和海翎光电的小编一起了解一下什么是VPN,VPN的分类。对基础知识有一定的了解后&#xff0c;我们再来讲一下VPN的盲点。 VPN(全称&#xff1a;Virtual Private Network)虚拟专用网络&#xff0c;是依靠ISP和其他的NSP&#xff0c;在公共网络中建立专用的数据通信的网络技术…

Linux 网络基础(2)应用层(http/https协议、请求格式、响应格式、session、cookie、加密传输)

说明&#xff1a;网络基础2讲解的是应用层的典型协议&#xff0c; 通过对于典型协议的理解&#xff0c;来体会数据的网络传输的软件层面的流程与原理。 面试中网络通信相关问题占了很大的比重&#xff0c;而网络通信相关的问题大多都集中在网络基础2这个单元中 下面是应用层的位…

解决dpdk reserve的内存返回的虚拟地址和iova地址一样的问题

1. 背景: 在ubuntu20.04上用dpdk API: rte_memzone_reserve_aligned("L1L2_PCIE_MEMORY", 1.5*1024*1024*1024, rte_socket_id(), RTE_MEMZONE_1GB|RTE_MEMZONE_IOVA_CONTIG, RTE_CACHE_LINE_SIZE); 分配1.5…

a-form中的label超出隐藏

效果 代码&#xff1a; :deep(.ant-form-item-label) {display: flex;justify-content: flex-end;line-height: 16px; //这个数值视具体情况而定label { //这是关键white-space: nowrap;text-align: right;// color: #8a8a8a;max-width: 150px;// padding-right: 3…

OpenCV+ Qt Designer 开发人脸识别考勤系统

文章目录 1. 系统介绍2. 系统架构3. 开发步骤3.1 安装必要的库3.2 设计用户界面3.3 编写代码3.3.1 导入库3.3.2 连接数据库3.3.3 定义主窗口类3.3.4 实时显示摄像头画面3.3.5 进行人脸识别3.3.6 手动打卡3.3.7 显示打卡时间3.3.8 显示图片3.3.9 运行主程序 4. 总结 1. 系统介绍…

day13 - 对指纹图片进行噪声消除

在指纹识别的过程中&#xff0c;指纹图片通常都是现场采集的&#xff0c;受环境的影响会有产生很多的噪声点&#xff0c;如果直接使用&#xff0c;会对指纹的识别产生很大的影响&#xff0c;而指纹识别的应用场景又都是一些比较严肃不容有错的场合&#xff0c;所以去除噪声又不…

MySQL——存储引擎与索引应用

文章目录 一、 存储引擎1.1 MySQL结构1.2 存储引擎简介1.3 存储引擎特点1.3.1 InnoDB1.3.1.1 InnoDB 基本介绍1.3.1.2 InnoDB 逻辑存储结构 1.3.2 MyISAM1.3.3 Memory 1.4 三种引擎特点及区别1.5 存储引擎选择 二、 索引 - 重点2.1 介绍2.2 索引结构2.2.1 B-Tree 多路平衡二叉树…

网络安全面试题汇总(附答案)

作为从业多年的网络安全工程师&#xff0c;我深知在面试过程中面试官所关注的重点及考察的技能点。网络安全作为当前信息技术领域中非常重要的一部分&#xff0c;对于每一个从事网络安全工作的人员来说&#xff0c;不仅需要掌握一定的技术能力&#xff0c;更需要具备全面的综合…

Python学习之pygame模块介绍并制作代码雨

前言 对Python游戏有所了解的朋友都知道&#xff0c;在2D的游戏制作中&#xff0c;经常会用到一个模块pygame&#xff0c;他能帮助我们实现很多方便使用的功能&#xff0c;例如绘制窗口&#xff0c;反馈键盘鼠标信息&#xff0c;播放音频文件&#xff0c;渲染图片文字等等功能…

Java接口测试实战:掌握JMeter技能,让测试更高效!

目录 引言 一.java环境搭建 二.操作示例 1.添加信息头 2.添加请求路径和请求参数 3.添加单个文件 4添加文件集合 三.实操注意事项 1.登录 1.1登录界面断言注意事项 1.2登录界面定义token 2.首页 2.1http请求只有路径 2.2需要引用token变量 3.产品管理 3.1增加产…

Acrel 2000E/G配电室综合监控系统

1、概述 在信息化建设中&#xff0c;配电室运行处于信息交换管理的核心位置&#xff0c;这就要求配电室内所有设备需要时时刻刻正常运转&#xff0c;一旦某台设备出现故障&#xff0c;对数据传输、存储及系统运行构成威胁&#xff0c;就会影响到全局&#xff0c;如果不能及时处…

python flask p5.js mysql 实现数据库查询并网页显示数据(后附完整代码分享)

tips&#xff1a;不涉及session&#xff0c;是纯简单数据共享 实现步骤&#xff1a; 第一步&#xff1a;搭建框架第二步&#xff1a;创建数据库第三步&#xff1a;设计前端网页第四步&#xff1a;后端实现存储数据库整体实现需要的代码文件: 第一步&#xff1a;搭建框架 首先f…

Unity-vr用眼睛注视选择物体

Unity-vr用眼睛注视选择物体 文章目录 Unity-vr用眼睛注视选择物体工程版本用法说明脚本说明WatchController - 注视主控制器WatchEvent - 注视事件WatchGameobject - 被注视物体TimerTool - 计时器工具 总结 工程版本 unity2019.4.9f1 vs2019 项目工程源代码下载 用法说明 …