• 粤嵌实训医疗项目--day03(Vue + SpringBoot)


     往期回顾

    粤嵌实训医疗项目day02(Vue + SpringBoot)-CSDN博客

    粤嵌实训医疗项目--day01(Vue+SpringBoot)-CSDN博客

    目录

    一、SpringBoot AOP的使用

    二、用户模块-注册功能(文件上传)

    三、用户模块-注册实现

    四、用户模块-登录-校验码


     

    一、项目SpringBoot AOP的使用(增添日志输出等)

    在vaccinum包下创建aspect包并输入以下代码

    1. @Aspect
    2. @Component
    3. public class LogAspect {
    4. private final static Logger LOG = LoggerFactory.getLogger(LogAspect.class);
    5. /** 定义一个切点 */
    6. @Pointcut("execution(public * com.example.vaccinum.controller..*Controller.*(..))")
    7. public void controllerPointcut() {}
    8. @Resource
    9. private SnowFlake snowFlake;
    10. @Before("controllerPointcut()")
    11. public void doBefore(JoinPoint joinPoint) throws Throwable {
    12. // 增加日志流水号
    13. MDC.put("LOG_ID", String.valueOf(snowFlake.nextId()));
    14. // 开始打印请求日志
    15. ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    16. HttpServletRequest request = attributes.getRequest();
    17. Signature signature = joinPoint.getSignature();
    18. String name = signature.getName();
    19. // 打印请求信息
    20. LOG.info("------------- 开始 -------------");
    21. LOG.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
    22. LOG.info("类名方法: {}.{}", signature.getDeclaringTypeName(), name);
    23. LOG.info("远程地址: {}", request.getRemoteAddr());
    24. RequestContext.setRemoteAddr(getRemoteIp(request));
    25. // 打印请求参数
    26. Object[] args = joinPoint.getArgs();
    27. // LOG.info("请求参数: {}", JSONObject.toJSONString(args));
    28. Object[] arguments = new Object[args.length];
    29. for (int i = 0; i < args.length; i++) {
    30. if (args[i] instanceof ServletRequest
    31. || args[i] instanceof ServletResponse
    32. || args[i] instanceof MultipartFile) {
    33. continue;
    34. }
    35. arguments[i] = args[i];
    36. }
    37. // 排除字段,敏感字段或太长的字段不显示
    38. String[] excludeProperties = {"password", "file"};
    39. PropertyPreFilters filters = new PropertyPreFilters();
    40. PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();
    41. excludefilter.addExcludes(excludeProperties);
    42. LOG.info("请求参数: {}", JSONObject.toJSONString(arguments, excludefilter));
    43. }
    44. @Around("controllerPointcut()")
    45. public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    46. long startTime = System.currentTimeMillis();
    47. Object result = proceedingJoinPoint.proceed();
    48. // 排除字段,敏感字段或太长的字段不显示
    49. String[] excludeProperties = {"password", "file"};
    50. PropertyPreFilters filters = new PropertyPreFilters();
    51. PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();
    52. excludefilter.addExcludes(excludeProperties);
    53. LOG.info("返回结果: {}", JSONObject.toJSONString(result, excludefilter));
    54. LOG.info("------------- 结束 耗时:{} ms -------------", System.currentTimeMillis() - startTime);
    55. return result;
    56. }
    57. /**
    58. * 使用nginx做反向代理,需要用该方法才能取到真实的远程IP
    59. * @param request
    60. * @return
    61. */
    62. public String getRemoteIp(HttpServletRequest request) {
    63. String ip = request.getHeader("x-forwarded-for");
    64. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
    65. ip = request.getHeader("Proxy-Client-IP");
    66. }
    67. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
    68. ip = request.getHeader("WL-Proxy-Client-IP");
    69. }
    70. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
    71. ip = request.getRemoteAddr();
    72. }
    73. return ip;
    74. }
    75. }

    再在vaccinum包下创建util包并引入两个类

    1.用于存储和获取当前请求的远程地址类RequestContext

    1. package com.example.vaccinum.util;
    2. import java.io.Serializable;
    3. public class RequestContext implements Serializable {
    4. private static ThreadLocal remoteAddr = new ThreadLocal<>();
    5. public static String getRemoteAddr() {
    6. return remoteAddr.get();
    7. }
    8. public static void setRemoteAddr(String remoteAddr) {
    9. RequestContext.remoteAddr.set(remoteAddr);
    10. }
    11. }

    2.雪花算法类SnowFlaske

    1. package com.example.vaccinum.util;
    2. import org.springframework.stereotype.Component;
    3. import java.text.ParseException;
    4. /**
    5. * Twitter的分布式自增ID雪花算法
    6. **/
    7. @Component
    8. public class SnowFlake {
    9. /**
    10. * 起始的时间戳
    11. */
    12. private final static long START_STMP = 1609459200000L; // 2021-01-01 00:00:00
    13. /**
    14. * 每一部分占用的位数
    15. */
    16. private final static long SEQUENCE_BIT = 12; //序列号占用的位数
    17. private final static long MACHINE_BIT = 5; //机器标识占用的位数
    18. private final static long DATACENTER_BIT = 5;//数据中心占用的位数
    19. /**
    20. * 每一部分的最大值
    21. */
    22. private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
    23. private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
    24. private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
    25. /**
    26. * 每一部分向左的位移
    27. */
    28. private final static long MACHINE_LEFT = SEQUENCE_BIT;
    29. private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    30. private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;
    31. private long datacenterId = 1; //数据中心
    32. private long machineId = 1; //机器标识
    33. private long sequence = 0L; //序列号
    34. private long lastStmp = -1L;//上一次时间戳
    35. public SnowFlake() {
    36. }
    37. public SnowFlake(long datacenterId, long machineId) {
    38. if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
    39. throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
    40. }
    41. if (machineId > MAX_MACHINE_NUM || machineId < 0) {
    42. throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
    43. }
    44. this.datacenterId = datacenterId;
    45. this.machineId = machineId;
    46. }
    47. /**
    48. * 产生下一个ID
    49. *
    50. * @return
    51. */
    52. public synchronized long nextId() {
    53. long currStmp = getNewstmp();
    54. if (currStmp < lastStmp) {
    55. throw new RuntimeException("Clock moved backwards. Refusing to generate id");
    56. }
    57. if (currStmp == lastStmp) {
    58. //相同毫秒内,序列号自增
    59. sequence = (sequence + 1) & MAX_SEQUENCE;
    60. //同一毫秒的序列数已经达到最大
    61. if (sequence == 0L) {
    62. currStmp = getNextMill();
    63. }
    64. } else {
    65. //不同毫秒内,序列号置为0
    66. sequence = 0L;
    67. }
    68. lastStmp = currStmp;
    69. return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
    70. | datacenterId << DATACENTER_LEFT //数据中心部分
    71. | machineId << MACHINE_LEFT //机器标识部分
    72. | sequence; //序列号部分
    73. }
    74. private long getNextMill() {
    75. long mill = getNewstmp();
    76. while (mill <= lastStmp) {
    77. mill = getNewstmp();
    78. }
    79. return mill;
    80. }
    81. private long getNewstmp() {
    82. return System.currentTimeMillis();
    83. }
    84. public static void main(String[] args) throws ParseException {
    85. // 时间戳
    86. // System.out.println(System.currentTimeMillis());
    87. // System.out.println(new Date().getTime());
    88. //
    89. // String dateTime = "2021-01-01 08:00:00";
    90. // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    91. // System.out.println(sdf.parse(dateTime).getTime());
    92. SnowFlake snowFlake = new SnowFlake(1, 1);
    93. long start = System.currentTimeMillis();
    94. for (int i = 0; i < 10; i++) {
    95. System.out.println(snowFlake.nextId());
    96. System.out.println(System.currentTimeMillis() - start);
    97. }
    98. }
    99. }

    还需要导入如下依赖

    1. <dependency>
    2. <groupId>org.springframework.bootgroupId>
    3. <artifactId>spring-boot-starter-aopartifactId>
    4. dependency>
    5. <dependency>
    6. <groupId>com.alibabagroupId>
    7. <artifactId>fastjsonartifactId>
    8. <version>1.2.70version>
    9. dependency>
    1. spring-boot-starter-aop:这是Spring Boot提供的一个AOP(面向切面编程)模块的启动器,它包含了Spring AOP和AspectJ等AOP框架的依赖,可以方便地在Spring Boot应用中使用AOP。AOP可以通过切面(Aspect)来实现横向逻辑的复用,比如日志记录、事务管理、权限控制等。

    2. fastjson:这是阿里巴巴开源的一个JSON序列化/反序列化框架,它可以将Java对象转换成JSON字符串,也可以将JSON字符串转换成Java对象。fastjson具有快速、稳定、高效的特点,广泛应用于Java应用的数据交换、RPC调用、消息队列等场景。在Spring Boot应用中,fastjson可以作为默认的JSON序列化/反序列化工具,也可以与其他JSON库一起使用。


    二、用户模块-注册功能(文件上传)

    --在controller层提供FileController文件上传的接口、在本地创建存储图片的文件夹

    1.创建上传图片接口

    1. @RestController
    2. @RequestMapping("/file")
    3. public class FileController {
    4. @RequestMapping("/upload")
    5. public String upload(MultipartFile file) throws IOException {
    6. String uuid = UUID.randomUUID().toString();
    7. // 1.1获取文件真实名称 123.jpg
    8. String filename = file.getOriginalFilename();
    9. // 2.图片名称修改
    10. // 后缀
    11. String substring = filename.substring(filename.lastIndexOf("."));
    12. // 拼接uuid和后缀名
    13. filename = uuid +substring;
    14. // 3.如何存到本地磁盘中 文件的上传
    15. file.transferTo(new File("E:\\实训\\upload\\"+filename));
    16. return "http://localhost:8085/" + filename;
    17. }
    18. }

    通过uuid类可以使得上传到本地磁盘文件名不会出现重复

    --在Login.vue提供对话框、在data中提供form变量

    找到Login.vue对应注册组件

    1. <el-dialog :visible.sync="dialogVisible" title="注册账号" width="30%">
    2. <el-form :model="form" label-width="120px">
    3. <el-form-item label="名称">
    4. <el-input v-model="form.name" style="width: 80%">el-input>
    5. el-form-item>
    6. <el-form-item label="手机号码">
    7. <el-input v-model="form.phone" style="width: 80%">el-input>
    8. el-form-item>
    9. <el-form-item label="密码">
    10. <el-input v-model="form.password" style="width: 80%">el-input>
    11. el-form-item>
    12. <el-form-item label="头像">
    13. <el-upload
    14. class="avatar-uploader"
    15. action="http://localhost:8088/file/upload/"
    16. :show-file-list="false"
    17. :on-success="handleAvatarSuccess"
    18. :before-upload="beforeAvatarUpload"
    19. >
    20. <img v-if="imageUrl" :src="imageUrl" class="avatar" />
    21. <i v-else class="el-icon-plus avatar-uploader-icon">i>
    22. el-upload>
    23. el-form-item>
    24. <el-form-item label="身份证号">
    25. <el-input v-model="form.code" style="width: 80%">el-input>
    26. el-form-item>
    27. <el-form-item label="邮箱">
    28. <el-input v-model="form.email" style="width: 80%">el-input>
    29. el-form-item>
    30. <el-form-item label="性别">
    31. <el-input v-model="form.sex" style="width: 80%">el-input>
    32. el-form-item>
    33. <el-form-item label="年龄">
    34. <el-input v-model="form.age" style="width: 80%">el-input>
    35. el-form-item>
    36. el-form>
    37. <template #footer>
    38. <span class="dialog-footer">
    39. <el-button @click="dialogVisible = false">取消el-button>
    40. <el-button type="primary" @click="save()">确定el-button>
    41. span>
    42. template>
    43. el-dialog>

    --在methods中提供上传的处理函数

     测试功能:

    可以看到成功上传成功并且展示出存放到磁盘中的图片


    三、用户模块-注册实现

    --在用户实体中提供主键字段

    在vaccinum架构下创建userInfo表单

    1. DROP TABLE IF EXISTS `user_info`;
    2. CREATE TABLE `user_info` (
    3. `user_id` bigint(20) NOT NULL COMMENT '用户id',
    4. `code` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '身份证',
    5. `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱',
    6. `sex` varchar(25) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '性别',
    7. `age` int(11) NULL DEFAULT NULL COMMENT '年龄',
    8. `job` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '职位',
    9. `status` int(11) NULL DEFAULT 0 COMMENT '用户通行码-0绿码-1黄码-2红码',
    10. PRIMARY KEY (`user_id`) USING BTREE
    11. ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户信息' ROW_FORMAT = DYNAMIC;
    12. -- ----------------------------
    13. -- Records of user_info
    14. -- ----------------------------
    15. INSERT INTO `user_info` VALUES (2, '456379865132485', '752963252@qq.com', '男', 45, '', 2);
    16. INSERT INTO `user_info` VALUES (3, '123465789651', '5689562@qq.com', '男', 16, NULL, 1);
    17. INSERT INTO `user_info` VALUES (9, '阿斯顿', 'asd', '女', 12, 'asd', 0);
    18. INSERT INTO `user_info` VALUES (10, '34', '34', '女', 3, '4', 0);
    19. INSERT INTO `user_info` VALUES (12, 'asd', 'asd', '男', 23, 'ghf', 0);
    20. INSERT INTO `user_info` VALUES (16, 'asd', 'asd', '男', 12, 'asd', 0);

    通过插件mbatisx使用逆向,自动创建对应三层架构的代码

    idea实现数据库连接

    下载完对应驱动后进行配置

    使用mybatisx插件

    mybatisx逆向配置

    创建完后对应userInfo实体类,需要进行修改

    1. @Data
    2. @EqualsAndHashCode(callSuper = false)
    3. public class UserInfo implements Serializable {
    4. private static final long serialVersionUID = 1L;
    5. /**
    6. * 用户id INPUT设置为手动输入id
    7. */
    8. @TableId(value = "user_id", type = IdType.INPUT)
    9. private Long userId;
    10. /**
    11. * username
    12. */
    13. @TableField(exist = false)
    14. private String userName;
    15. /**
    16. * 身份证
    17. */
    18. private String code;
    19. /**
    20. * 邮箱
    21. */
    22. private String email;
    23. /**
    24. * 性别
    25. */
    26. private String sex;
    27. /**
    28. * 年龄
    29. */
    30. private Integer age;
    31. /**
    32. * 职位
    33. */
    34. private String job;
    35. /**
    36. * 用户通行码-0绿码-1黄码-2红码
    37. */
    38. private Integer status;
    39. @TableField(exist = false)
    40. private User user;
    41. }

    在启动类中添加扫描mapper的注解

    --在用户controller中提供注册接口

    1. @Autowired
    2. UserInfoService userInfoService;
    3. //定义一个请求接口来实现用户的注册 user、userinfo
    4. @RequestMapping("/register")
    5. public String register(User user,UserInfo userInfo) throws JsonProcessingException {
    6. // 1.创建json解析工具
    7. ObjectMapper json = new ObjectMapper();
    8. // 2.返回的结果集
    9. HashMap map = new HashMap<>();
    10. // 3.调用方法添加数据
    11. boolean save = userService.save(user);
    12. // 4.添加userInfo的数据 需要设置 user的id主键 为 userinfo id的值
    13. userInfo.setUserId(user.getId());
    14. boolean save1 = userInfoService.save(userInfo);
    15. // 响应结果
    16. map.put("flag",save&&save1);
    17. // 返回解析好的json数据
    18. return json.writeValueAsString(map);
    19. }

    前端设置好请求

    --在文件上传成功后,把服务器响应的图片url赋值到form.image

    --修改页面提供save函数和异步请求操作 

    1. //注册的函数
    2. save() {
    3. //发起一个异步请求,查询分类的数据
    4. request
    5. // post 请求方式
    6. .post("/gec/user/register", this.form)
    7. // then表示请求后的回调函数
    8. .then((res) => {
    9. //判断操作是否成功
    10. if (res.ok == true) {
    11. //消息提示
    12. this.$message({
    13. message: "注册成功",
    14. type: "success",
    15. });
    16. //把form的数据清空
    17. this.form = {
    18. name: "",
    19. phone: "",
    20. password: "",
    21. image: "",
    22. code: "",
    23. email: "",
    24. sex: "",
    25. age: "",
    26. };
    27. //关闭对话框
    28. this.dialogVisible = false;
    29. } else {
    30. this.$message.error("注册失败");
    31. }
    32. });
    33. },

    功能展示:

    前端展示:

    数据库展示:


    四、用户模块-登录-校验码

    在项目中的resource下创建lib包并设置为库,放入以下两个jar包

    检测是否变成库

    --在项目中提供验证码的controller接口【注意使用:jdk8】

    1. import com.fasterxml.jackson.databind.ObjectMapper;
    2. import com.google.code.kaptcha.impl.DefaultKaptcha;
    3. import com.google.code.kaptcha.util.Config;
    4. import org.springframework.web.bind.annotation.RequestMapping;
    5. import org.springframework.web.bind.annotation.RestController;
    6. //sun.misc.BASE64Encoder jdk8提供
    7. import sun.misc.BASE64Encoder;
    8. import javax.imageio.ImageIO;
    9. import javax.servlet.http.HttpServletRequest;
    10. import javax.servlet.http.HttpServletResponse;
    11. import java.awt.image.BufferedImage;
    12. import java.io.ByteArrayOutputStream;
    13. import java.io.IOException;
    14. import java.util.HashMap;
    15. import java.util.Properties;
    16. @RestController
    17. @RequestMapping("/captcha")
    18. public class CaptchaController {
    19. //返回验证码
    20. @RequestMapping("/getCaptcha")
    21. public void getCaptcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
    22. //验证码生成器
    23. DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
    24. //配置
    25. Properties properties = new Properties();
    26. //是否有边框
    27. properties.setProperty("kaptcha.border", "yes");
    28. //设置边框颜色
    29. properties.setProperty("kaptcha.border.color", "105,179,90");
    30. //边框粗细度,默认为1
    31. // properties.setProperty("kaptcha.border.thickness","1");
    32. //验证码
    33. properties.setProperty("kaptcha.session.key", "code");
    34. //验证码文本字符颜色 默认为黑色
    35. properties.setProperty("kaptcha.textproducer.font.color", "blue");
    36. //设置字体样式
    37. properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅 黑");
    38. //字体大小,默认40
    39. properties.setProperty("kaptcha.textproducer.font.size", "30");
    40. //验证码文本字符内容范围 默认为abced2345678gfynmnpwx
    41. // properties.setProperty("kaptcha.textproducer.char.string", "");
    42. //字符长度,默认为5
    43. properties.setProperty("kaptcha.textproducer.char.length", "4");
    44. //字符间距 默认为2
    45. properties.setProperty("kaptcha.textproducer.char.space", "4");
    46. //验证码图片宽度 默认为200
    47. properties.setProperty("kaptcha.image.width", "100");
    48. //验证码图片高度 默认为40
    49. properties.setProperty("kaptcha.image.height", "40");
    50. Config config = new Config(properties); //当前对象包引用路径 为 google
    51. defaultKaptcha.setConfig(config);
    52. //定义response输出类型为image/jpeg
    53. response.setDateHeader("Expires", 0);
    54. response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
    55. response.addHeader("Cache-Control", "post-check=0, pre-check=0");
    56. response.setHeader("Pragma", "no-cache");
    57. response.setContentType("image/jpeg");
    58. //---------------------------生成验证码----------------------
    59. //获取验证码文本内容
    60. String text = defaultKaptcha.createText();
    61. System.out.println("验证码: " + text);
    62. //captcha作为key,将验证码放到session中
    63. request.getSession().setAttribute("captcha", text);
    64. //根据文本内容创建图形验证码
    65. BufferedImage image = defaultKaptcha.createImage(text);
    66. //创建IO流
    67. ByteArrayOutputStream baos = new ByteArrayOutputStream();
    68. try {
    69. //输出流输出图片,格式为jpg
    70. ImageIO.write(image, "jpg", baos);
    71. } catch (IOException e) {
    72. e.printStackTrace();
    73. }
    74. byte[] bytes = baos.toByteArray();//把流转换成字节数组
    75. BASE64Encoder encoder = new BASE64Encoder();
    76. String imgStr = encoder.encodeBuffer(bytes).trim();
    77. System.out.println(imgStr);
    78. HashMap map = new HashMap<>();
    79. map.put("code", 200);
    80. map.put("imgStr", imgStr);
    81. ObjectMapper objectMapper = new ObjectMapper();
    82. String json = objectMapper.writeValueAsString(map);
    83. response.getWriter().println(json);
    84. }
    85. }

    --在用户controller中修改登录请求

    1. //定义一个请求接口来实现用户登录
    2. @RequestMapping("login")
    3. public String login(String phone, String password, String code, HttpSession session) throws JsonProcessingException {
    4. //定义json解析工具
    5. ObjectMapper objectMapper = new ObjectMapper();
    6. //key-value集合结果
    7. HashMap result = new HashMap();
    8. //获取正确的验证码
    9. String captcha = (String) session.getAttribute("captcha");
    10. // 进行验证码判断
    11. if(!code.equals(captcha)){
    12. //保存到map中
    13. result.put("ok", false);
    14. result.put("message", "验证码错误");
    15. //返回解析的json数据
    16. return objectMapper.writeValueAsString(result);
    17. }
    18. //调用业务层的方法进行登录查询 【手机号码、密码】
    19. QueryWrapper userQueryWrapper = new QueryWrapper<>();
    20. userQueryWrapper.eq("phone", phone);
    21. userQueryWrapper.eq("password", password);
    22. //根据条件进行查询
    23. User user = userService.getOne(userQueryWrapper);
    24. //判断
    25. if (user != null) {//登录成功
    26. //保存到map中
    27. result.put("ok", true);
    28. result.put("user", user);
    29. } else {
    30. result.put("ok", false);
    31. result.put("message", "用户名或密码错误");
    32. }
    33. //返回解析的json数据
    34. return objectMapper.writeValueAsString(result);
    35. }

    --在script中提供生命周期、及获取验证码的函数

    1. created() {
    2. this.getCode();
    3. //this.getCookie();
    4. },
    1. getCode() {
    2. request.get("/captcha/getCaptcha").then((res) => {
    3. console.log("res:", res);
    4. if (res.code == "200") {
    5. this.codeUrl = "data:image/jpg;base64," + res.imgStr;
    6. }
    7. });
    8. },

    效果展示 :

    验证码判断

    正确验证码与正确账号密码下正常登陆。


  • 相关阅读:
    Spring高手之路11——BeanDefinition解密:构建和管理Spring Beans的基石
    Ant Design Pro【面包屑导航】二级路由和三级路由都有component的情况,三级不显示component的页面,怎么解决?
    基于JAVA医院远程诊断系统计算机毕业设计源码+系统+mysql数据库+lw文档+部署
    基于ASAM ODS标准的试验数字化平台-WDP
    第71步 时间序列建模实战:ARIMA建模(Python)
    golang 使用 viper 加载配置文件 自动反序列化到结构
    C++ Standard Template Libaray(STL)迭代器演示源代码
    2022版:Gitee在Android studio上的使用
    基于最小二乘支持向量机(LS-SVM)进行分类、函数估计、时间序列预测和无监督学习(Matlab代码实现)
    毫米波雷达基础知识系列——FFT
  • 原文地址:https://blog.csdn.net/dogxixi/article/details/134096079