From 23603498db6bc186eb7fe1e2757f77dd5419236c Mon Sep 17 00:00:00 2001
From: XiaoRuby <3114200645@qq.com>
Date: 星期三, 05 七月 2023 13:44:19 +0800
Subject: [PATCH] LIMS管理系统框架1.0.0

---
 user-server/src/main/java/com/yuanchu/limslaboratory/controller/AdminController.java    |   70 ++
 framework/src/main/java/com/yuanchu/limslaboratory/utils/RedisUtil.java                 |  622 +++++++++++++++++++
 framework/src/main/java/com/yuanchu/limslaboratory/config/MyBatisPlusConfig.java        |   18 
 user-server/src/main/java/com/yuanchu/limslaboratory/clients/UserClient.java            |   19 
 sys/src/test/java/com/yuanchu/limslaboratory/SysApplicationTests.java                   |   16 
 sys/src/main/java/com/yuanchu/limslaboratory/SysApplication.java                        |   13 
 framework/src/main/java/com/yuanchu/limslaboratory/config/MyCorsConfig.java             |   37 +
 user-server/src/main/java/com/yuanchu/limslaboratory/clients/UserLoginUtils.java        |   73 ++
 framework/src/main/java/com/yuanchu/limslaboratory/utils/JackSonUtil.java               |  123 +++
 framework/src/main/java/com/yuanchu/limslaboratory/config/WebMvcConfig.java             |   26 
 user-server/src/main/java/com/yuanchu/limslaboratory/mapper/AdminMapper.java            |   16 
 framework/src/main/java/com/yuanchu/limslaboratory/config/DruidConfig.java              |   57 +
 framework/src/main/java/com/yuanchu/limslaboratory/utils/MyUtils.java                   |   65 ++
 framework/src/main/java/com/yuanchu/limslaboratory/utils/SpringUtils.java               |   51 +
 framework/src/main/java/com/yuanchu/limslaboratory/handler/GlobalExceptionHandler.java  |  164 +++++
 user-server/src/main/java/com/yuanchu/limslaboratory/service/AdminService.java          |   16 
 framework/src/main/java/com/yuanchu/limslaboratory/vo/Result.java                       |   53 +
 sys/src/test/java/com/yuanchu/limslaboratory/CodeGenerator.java                         |  129 ++++
 user-server/src/main/java/com/yuanchu/limslaboratory/service/impl/AdminServiceImpl.java |   20 
 user-server/src/main/java/com/yuanchu/limslaboratory/config/FeignConfig.java            |   37 +
 framework/src/main/java/com/yuanchu/limslaboratory/utils/FileSaveUtils.java             |   60 +
 framework/src/main/java/com/yuanchu/limslaboratory/utils/JwtUtils.java                  |   37 +
 user-server/src/main/java/com/yuanchu/limslaboratory/pojo/Admin.java                    |   52 +
 framework/src/main/java/com/yuanchu/limslaboratory/handler/MyMetaObjectHandler.java     |   22 
 framework/src/main/java/com/yuanchu/limslaboratory/config/Swagger3.java                 |  122 +++
 25 files changed, 1,918 insertions(+), 0 deletions(-)

diff --git a/framework/src/main/java/com/yuanchu/limslaboratory/config/DruidConfig.java b/framework/src/main/java/com/yuanchu/limslaboratory/config/DruidConfig.java
new file mode 100644
index 0000000..75e7058
--- /dev/null
+++ b/framework/src/main/java/com/yuanchu/limslaboratory/config/DruidConfig.java
@@ -0,0 +1,57 @@
+package com.yuanchu.limslaboratory.config;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.druid.support.http.StatViewServlet;
+import com.alibaba.druid.support.http.WebStatFilter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.sql.DataSource;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+@Configuration
+public class DruidConfig {
+    //鍔犺浇application.yaml涓殑Druid閰嶇疆
+    @ConfigurationProperties(prefix = "spring.datasource")
+    @Bean
+    public DataSource druid(){
+        return  new DruidDataSource();
+    }
+
+    //閰嶇疆Druid鐨勭洃鎺�
+    //1銆侀厤缃竴涓鐞嗗悗鍙扮殑Servlet
+    @Bean
+    public ServletRegistrationBean statViewServlet(){
+        ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
+        Map<String,String> initParams = new HashMap<>();
+
+        initParams.put("loginUsername","root");
+        initParams.put("loginPassword","123456");
+        initParams.put("allow","");//榛樿灏辨槸鍏佽鎵�鏈夎闂�
+//        initParams.put("deny","192.168.15.21"); 绂佹璇P璁块棶
+
+        bean.setInitParameters(initParams);
+        return bean;
+    }
+
+    //2銆侀厤缃竴涓獁eb鐩戞帶鐨刦ilter
+    @Bean
+    public FilterRegistrationBean webStatFilter(){
+        FilterRegistrationBean bean = new FilterRegistrationBean();
+        bean.setFilter(new WebStatFilter());
+
+        Map<String,String> initParams = new HashMap<>();
+        initParams.put("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
+
+        bean.setInitParameters(initParams);
+
+        bean.setUrlPatterns(Arrays.asList("/*"));
+
+        return bean;
+    }
+}
diff --git a/framework/src/main/java/com/yuanchu/limslaboratory/config/MyBatisPlusConfig.java b/framework/src/main/java/com/yuanchu/limslaboratory/config/MyBatisPlusConfig.java
new file mode 100644
index 0000000..56853a6
--- /dev/null
+++ b/framework/src/main/java/com/yuanchu/limslaboratory/config/MyBatisPlusConfig.java
@@ -0,0 +1,18 @@
+package com.yuanchu.limslaboratory.config;
+
+import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@MapperScan("com.yuanchu.limslaboratory.mapper") // 鎵弿Mybatis涓殑mapper鍖�
+@Configuration
+public class MyBatisPlusConfig {
+
+//     涔愯閿佹彃浠�
+    @Bean
+    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
+        return new OptimisticLockerInterceptor();
+    }
+}
diff --git a/framework/src/main/java/com/yuanchu/limslaboratory/config/MyCorsConfig.java b/framework/src/main/java/com/yuanchu/limslaboratory/config/MyCorsConfig.java
new file mode 100644
index 0000000..e9ccacb
--- /dev/null
+++ b/framework/src/main/java/com/yuanchu/limslaboratory/config/MyCorsConfig.java
@@ -0,0 +1,37 @@
+package com.yuanchu.limslaboratory.config;
+
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+
+@Configuration
+public class MyCorsConfig {
+
+    private CorsConfiguration buildConfig() {
+        CorsConfiguration corsConfiguration = new CorsConfiguration();
+        // 1 璁剧疆璁块棶婧愬湴鍧�
+        corsConfiguration.addAllowedOrigin("*");
+        // 2 璁剧疆璁块棶婧愯姹傚ご
+        corsConfiguration.addAllowedHeader("*");
+        // 3 璁剧疆璁块棶婧愯姹傛柟娉�
+        corsConfiguration.addAllowedMethod("*");
+        // 4 鏆撮湶鍝簺澶撮儴淇℃伅
+//        corsConfiguration.addExposedHeader(JwtConstant.HEADER);
+        return corsConfiguration;
+    }
+    @Bean
+    public FilterRegistrationBean<CorsFilter> corsFilter() {
+//        log.info("璺ㄥ煙璁剧疆銆傘�傘�傘��");
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+        // 5 瀵规帴鍙i厤缃法鍩熻缃�
+        source.registerCorsConfiguration("/**", buildConfig());
+        //鏈夊涓猣ilter鏃舵澶勮缃敼CorsFilter鐨勪紭鍏堟墽琛岄『搴�
+        FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
+        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
+        return bean;
+    }
+}
diff --git a/framework/src/main/java/com/yuanchu/limslaboratory/config/Swagger3.java b/framework/src/main/java/com/yuanchu/limslaboratory/config/Swagger3.java
new file mode 100644
index 0000000..29954ad
--- /dev/null
+++ b/framework/src/main/java/com/yuanchu/limslaboratory/config/Swagger3.java
@@ -0,0 +1,122 @@
+package com.yuanchu.limslaboratory.config;
+
+
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.oas.annotations.EnableOpenApi;
+import springfox.documentation.service.*;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
+import springfox.documentation.spring.web.plugins.Docket;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Configuration
+@EnableOpenApi
+public class Swagger3 {
+    // 璺緞http://localhost:8080/doc.html
+    @Value("${swagger.enabled}")
+    private boolean enable;
+
+    private final String swaggerPackage = "com.yuanchu.limslaboratory";
+
+    /**
+     * 娣诲姞鎽樿淇℃伅
+     */
+    private ApiInfo apiInfo() {
+        // 鐢ˋpiInfoBuilder杩涜瀹氬埗
+        return new ApiInfoBuilder()
+                // 璁剧疆鏍囬
+                .title("姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃绠$悊绯荤粺")
+                // 鎻忚堪
+                .description("姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃绠$悊绯荤粺")
+                // 浣滆�呬俊鎭�
+                .contact(new Contact("Crunchy", null, null))
+                // 鐗堟湰
+                .version("鐗堟湰鍙�:V.1")
+                //鍗忚
+                .license("The Apache License")
+                //鍗忚url
+                .licenseUrl("http://www.baidu.com")
+                .build();
+    }
+
+    /**
+     * 鍒涘缓API
+     * http:IP:绔彛鍙�/swagger-ui/index.html 鍘熺敓鍦板潃
+     * http:IP:绔彛鍙�/doc.html bootStrap-UI鍦板潃
+     */
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.OAS_30).pathMapping("/")
+                // 鐢ㄦ潵鍒涘缓璇PI鐨勫熀鏈俊鎭紝灞曠ず鍦ㄦ枃妗g殑椤甸潰涓紙鑷畾涔夊睍绀虹殑淇℃伅锛�
+                .enable(enable)
+                .apiInfo(apiInfo())
+                // 璁剧疆鍝簺鎺ュ彛鏆撮湶缁橲wagger灞曠ず
+                .select()
+                // 鎵弿鎵�鏈夋湁娉ㄨВ鐨刟pi锛岀敤杩欑鏂瑰紡鏇寸伒娲�
+                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+
+
+                // 鎵弿鎸囧畾鍖呬腑鐨剆wagger娉ㄨВ
+                .apis(RequestHandlerSelectors.basePackage(swaggerPackage))
+                // 鎵弿鎵�鏈� .apis(RequestHandlerSelectors.any())
+                .paths(PathSelectors.regex("(?!/ApiError.*).*"))
+                .paths(PathSelectors.any())
+                .build()
+                // 鏀寔鐨勯�氳鍗忚闆嗗悎
+                .protocols(newHashSet("https", "http"))
+                .securitySchemes(securitySchemes())
+                .securityContexts(securityContexts());
+    }
+
+    /**
+     * 鏀寔鐨勯�氳鍗忚闆嗗悎
+     * @param type1
+     * @param type2
+     * @return
+     */
+    private Set<String> newHashSet(String type1, String type2){
+        Set<String> set = new HashSet<>();
+        set.add(type1);
+        set.add(type2);
+        return set;
+    }
+
+    /**
+     * 璁よ瘉鐨勫畨鍏ㄤ笂涓嬫枃
+     */
+    private List<SecurityScheme> securitySchemes() {
+        List<SecurityScheme> securitySchemes = new ArrayList<>();
+        securitySchemes.add((SecurityScheme) new ApiKey("token", "token", "header"));
+        return securitySchemes;
+    }
+
+    /**
+     * 鎺堟潈淇℃伅鍏ㄥ眬搴旂敤
+     */
+    private List<SecurityContext> securityContexts() {
+        List<SecurityContext> securityContexts = new ArrayList<>();
+        securityContexts.add(SecurityContext.builder()
+                .securityReferences(defaultAuth())
+                .forPaths(PathSelectors.any()).build());
+        return securityContexts;
+    }
+
+    private List<SecurityReference> defaultAuth() {
+        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
+        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
+        authorizationScopes[0] = authorizationScope;
+        List<SecurityReference> securityReferences = new ArrayList<>();
+        securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
+        return securityReferences;
+    }
+}
diff --git a/framework/src/main/java/com/yuanchu/limslaboratory/config/WebMvcConfig.java b/framework/src/main/java/com/yuanchu/limslaboratory/config/WebMvcConfig.java
new file mode 100644
index 0000000..560b57f
--- /dev/null
+++ b/framework/src/main/java/com/yuanchu/limslaboratory/config/WebMvcConfig.java
@@ -0,0 +1,26 @@
+package com.yuanchu.limslaboratory.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
+
+import java.io.File;
+
+@Configuration
+public class WebMvcConfig extends WebMvcConfigurationSupport {
+
+    @Override
+    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
+        // swagger鍙鍖栭厤缃�
+        registry.addResourceHandler("/systemPictures/**")
+                .addResourceLocations("file:" + System.getProperty("user.dir")+ File.separator+"uploadFile"+File.separator+"systemPictures"+File.separator);
+        registry.addResourceHandler("/uploadFile/pluginFiles/logo/**")
+                .addResourceLocations("file:" + System.getProperty("user.dir")+ File.separator+"uploadFile"+File.separator+"pluginFiles"+File.separator+"logo"+File.separator);
+
+        registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
+        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
+
+        //璁剧疆鏂囦欢铏氭嫙璺緞鏄犲皠
+        registry.addResourceHandler("/img/**").addResourceLocations("file:E:\\webapp\\images\\");
+    }
+}
diff --git a/framework/src/main/java/com/yuanchu/limslaboratory/handler/GlobalExceptionHandler.java b/framework/src/main/java/com/yuanchu/limslaboratory/handler/GlobalExceptionHandler.java
new file mode 100644
index 0000000..0dc2db3
--- /dev/null
+++ b/framework/src/main/java/com/yuanchu/limslaboratory/handler/GlobalExceptionHandler.java
@@ -0,0 +1,164 @@
+package com.yuanchu.limslaboratory.handler;
+
+import com.yuanchu.limslaboratory.vo.Result;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.ConversionNotSupportedException;
+import org.springframework.beans.TypeMismatchException;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.http.converter.HttpMessageNotWritableException;
+import org.springframework.jdbc.BadSqlGrammarException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.sql.SQLException;
+
+
+@Slf4j
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+    @ExceptionHandler(SQLException.class)
+    public Result<?> handlerSQLException(SQLException e)
+    {
+        log.error(e.getMessage().toLowerCase(), e);
+        return Result.fail("鏁版嵁鎿嶄綔澶辫触锛佽鑱旂郴绠$悊鍛�");
+    }
+
+    /**
+     * 鍞竴鍊煎湪鏁版嵁搴撲腑閲嶅
+     * Duplicate entry ' ' for key ' '
+     * @param e锛氶噸澶嶉敭寮傚父
+     * @return 199
+     */
+    @ExceptionHandler
+    public Result<?> DuplicateKeyException(DuplicateKeyException e) {
+        log.error(String.valueOf(e));
+        String message = e.getCause().getMessage();
+        String[] split = message.split("'");
+        return Result.fail("閲嶅娣诲姞锛氥��" + split[1] + "銆戞搷浣滃け璐ワ紒");
+    }
+
+    @ExceptionHandler
+    public Result<?> NullPointerException(NullPointerException e){
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("閮ㄥ垎鍙傛暟涓虹┖锛岃妫�鏌ワ紒");
+    }
+
+    /** 杩愯鏃跺紓甯� */
+    @ExceptionHandler(RuntimeException.class)
+    public Result<?> runtimeExceptionHandler(RuntimeException e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("杩愯鏃跺紓甯�");
+    }
+
+    /** 绫诲瀷杞崲寮傚父 */
+    @ExceptionHandler(ClassCastException.class)
+    public Result<?> classCastExceptionHandler(ClassCastException e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("绫诲瀷杞崲寮傚父");
+    }
+    /** 鏂囦欢鏈壘鍒板紓甯� */
+    @ExceptionHandler(FileNotFoundException.class)
+    public Result<?> FileNotFoundException(FileNotFoundException e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("鏂囦欢鏈壘鍒板紓甯�");
+    }
+    /** 鏁板瓧鏍煎紡寮傚父 */
+    @ExceptionHandler(NumberFormatException.class)
+    public Result<?> NumberFormatException(NumberFormatException e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("鏁板瓧鏍煎紡寮傚父");
+    }
+    /** 瀹夊叏寮傚父 */
+    @ExceptionHandler(SecurityException.class)
+    public Result<?> SecurityException(SecurityException e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("瀹夊叏寮傚父");
+    }
+
+    /** 绫诲瀷涓嶅瓨鍦ㄥ紓甯� */
+    @ExceptionHandler(TypeNotPresentException.class)
+    public Result<?> TypeNotPresentException(TypeNotPresentException e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("绫诲瀷涓嶅瓨鍦ㄥ紓甯�");
+    }
+
+    /** IO寮傚父 */
+    @ExceptionHandler(IOException.class)
+    public Result<?> iOExceptionHandler(IOException e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("IO寮傚父");
+    }
+
+    /** 鏈煡鏂规硶寮傚父 */
+    @ExceptionHandler(NoSuchMethodException.class)
+    public Result<?> noSuchMethodExceptionHandler(NoSuchMethodException e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("鏈煡鏂规硶寮傚父");
+    }
+
+    /** 鏁扮粍瓒婄晫寮傚父 */
+    @ExceptionHandler(IndexOutOfBoundsException.class)
+    public Result<?> indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("鏁扮粍瓒婄晫寮傚父");
+    }
+    /** sql璇硶閿欒寮傚父 */
+    @ExceptionHandler(BadSqlGrammarException.class)
+    public Result<?> BadSqlGrammarException(BadSqlGrammarException e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("sql璇硶閿欒寮傚父");
+    }
+
+    /** 鏃犳硶娉ㄥ叆bean寮傚父 */
+    @ExceptionHandler(NoSuchBeanDefinitionException.class)
+    public Result<?> NoSuchBeanDefinitionException(NoSuchBeanDefinitionException e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("鏃犳硶娉ㄥ叆bean");
+    }
+
+    /** Http娑堟伅涓嶅彲璇诲紓甯� */
+    @ExceptionHandler({HttpMessageNotReadableException.class})
+    public Result<?> requestNotReadable(HttpMessageNotReadableException e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("Http娑堟伅涓嶅彲璇�");
+    }
+
+    /** 400閿欒 */
+    @ExceptionHandler({TypeMismatchException.class})
+    public Result<?> requestTypeMismatch(TypeMismatchException e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("鏈嶅姟鍣ㄥ紓甯�");
+    }
+
+    /** 500閿欒 */
+    @ExceptionHandler({ConversionNotSupportedException.class, HttpMessageNotWritableException.class})
+    public Result<?> server500(RuntimeException e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("鏈嶅姟鍣ㄥ紓甯�");
+    }
+
+    /** 鏍堟孩鍑� */
+    @ExceptionHandler({StackOverflowError.class})
+    public Result<?> requestStackOverflow(StackOverflowError e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("鏍堟孩鍑哄紓甯�");
+    }
+
+    /** 闄ゆ暟涓嶈兘涓�0 */
+    @ExceptionHandler({ArithmeticException.class})
+    public Result<?> arithmeticException(ArithmeticException e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("闄ゆ暟涓嶈兘涓�0寮傚父");
+    }
+
+    /** 鍏朵粬閿欒 */
+    @ExceptionHandler({Exception.class})
+    public Result<?> exception(Exception e) {
+        log.error(e.getMessage(), e.getCause());
+        return Result.fail("缃戠粶杩炴帴澶辫触锛岃閫�鍑哄悗鍐嶈瘯");
+    }
+}
diff --git a/framework/src/main/java/com/yuanchu/limslaboratory/handler/MyMetaObjectHandler.java b/framework/src/main/java/com/yuanchu/limslaboratory/handler/MyMetaObjectHandler.java
new file mode 100644
index 0000000..03566f9
--- /dev/null
+++ b/framework/src/main/java/com/yuanchu/limslaboratory/handler/MyMetaObjectHandler.java
@@ -0,0 +1,22 @@
+package com.yuanchu.limslaboratory.handler;
+
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import org.apache.ibatis.reflection.MetaObject;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+
+@Component
+public class MyMetaObjectHandler implements MetaObjectHandler {
+    @Override
+    public void insertFill(MetaObject metaObject) {
+        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 璧峰鐗堟湰 3.3.0(鎺ㄨ崘浣跨敤)
+        this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 璧峰鐗堟湰 3.3.0(鎺ㄨ崘浣跨敤)
+    }
+
+    @Override
+    public void updateFill(MetaObject metaObject) {
+        // update鐨勬椂鍊欎娇鐢紝鏇存柊鐨勬椂鍊欏己鍒惰繘琛屽~鍏�
+        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 璧峰鐗堟湰 3.3.0(鎺ㄨ崘)
+    }
+}
diff --git a/framework/src/main/java/com/yuanchu/limslaboratory/utils/FileSaveUtils.java b/framework/src/main/java/com/yuanchu/limslaboratory/utils/FileSaveUtils.java
new file mode 100644
index 0000000..d06b77a
--- /dev/null
+++ b/framework/src/main/java/com/yuanchu/limslaboratory/utils/FileSaveUtils.java
@@ -0,0 +1,60 @@
+package com.yuanchu.limslaboratory.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.tomcat.util.http.fileupload.IOUtils;
+import org.springframework.stereotype.Component;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * 淇濆瓨鏂囦欢宸ュ叿
+ */
+@Slf4j
+@Component
+public class FileSaveUtils {
+
+    // 鍙杫ml涓殑璺緞 + /
+//    @Value("${file.path}")
+    private String FILE_PATH;
+
+    /**
+     * 瀛樺偍鏂囦欢涓诲嚱鏁�
+     * @param content 鏂囦欢浜岃繘鍒舵祦
+     * @param originalFilename 鏂囦欢鍚嶇О
+     * @return 杩斿洖鏂囦欢鍚嶇О鐢ㄤ簬瀛樺偍鏁版嵁搴�
+     */
+    public String StoreFile(byte[] content, String originalFilename) {
+        // 鐢熸垚闅忔満鍚嶇О锛氭椂闂確闅忔満6浣嶆暟瀛�
+        String FileName = System.currentTimeMillis() + "_" + MyUtils.getNumber(6);
+        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
+        // 鍚嶇О鎷兼帴
+        String fileName = FileName + suffix;
+        // 杩涜瀛樺偍
+        storeFileWithFileName(content, fileName);
+        return fileName;
+    }
+
+    /**
+     * 瀛樺偍鏂囦欢鍑芥暟
+     * @param content 鏂囦欢浜岃繘鍒舵祦
+     * @param fileName 鏂囦欢鍚嶇О
+     */
+    private void storeFileWithFileName(byte[] content, String fileName) {
+        // 瀛樺偍璺緞
+        String path = FILE_PATH + java.io.File.separatorChar;
+        // 鐩綍涓嶅瓨鍦ㄥ垯鍒涘缓
+        java.io.File file = new java.io.File(path);
+        if (!file.exists()) {
+            file.mkdirs();
+        }
+        // 寮�濮嬪瓨鍌�
+        try (FileOutputStream os = new FileOutputStream(path + fileName);
+             ByteArrayInputStream is = new ByteArrayInputStream(content)) {
+             IOUtils.copy(is, os);
+        } catch (IOException e) {
+            MyUtils.PrintLog("瀛樺偍鏂囦欢寮傚父锛�" + e);
+        }
+    }
+}
diff --git a/framework/src/main/java/com/yuanchu/limslaboratory/utils/JackSonUtil.java b/framework/src/main/java/com/yuanchu/limslaboratory/utils/JackSonUtil.java
new file mode 100644
index 0000000..837d6b9
--- /dev/null
+++ b/framework/src/main/java/com/yuanchu/limslaboratory/utils/JackSonUtil.java
@@ -0,0 +1,123 @@
+package com.yuanchu.limslaboratory.utils;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * JSON瑙f瀽澶勭悊
+ *
+ * @author 寮犲
+ */
+@Component
+public class JackSonUtil {
+    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+    private static final ObjectWriter OBJECT_WRITER = OBJECT_MAPPER.writerWithDefaultPrettyPrinter();
+
+    public static void marshal(File file, Object value) throws Exception {
+        try {
+            OBJECT_WRITER.writeValue(file, value);
+        } catch (JsonGenerationException e) {
+            throw new Exception(e);
+        } catch (JsonMappingException e) {
+            throw new Exception(e);
+        } catch (IOException e) {
+            throw new Exception(e);
+        }
+    }
+
+    public static void marshal(OutputStream os, Object value) throws Exception {
+        try {
+            OBJECT_WRITER.writeValue(os, value);
+        } catch (JsonGenerationException e) {
+            throw new Exception(e);
+        } catch (JsonMappingException e) {
+            throw new Exception(e);
+        } catch (IOException e) {
+            throw new Exception(e);
+        }
+    }
+
+    public static String marshal(Object value) throws Exception {
+        try {
+            return OBJECT_WRITER.writeValueAsString(value);
+        } catch (JsonGenerationException e) {
+            throw new Exception(e);
+        } catch (JsonMappingException e) {
+            throw new Exception(e);
+        } catch (IOException e) {
+            throw new Exception(e);
+        }
+    }
+
+    public static byte[] marshalBytes(Object value) throws Exception {
+        try {
+            return OBJECT_WRITER.writeValueAsBytes(value);
+        } catch (JsonGenerationException e) {
+            throw new Exception(e);
+        } catch (JsonMappingException e) {
+            throw new Exception(e);
+        } catch (IOException e) {
+            throw new Exception(e);
+        }
+    }
+
+    public static <T> T unmarshal(File file, Class<T> valueType) throws Exception {
+        try {
+            return OBJECT_MAPPER.readValue(file, valueType);
+        } catch (JsonParseException e) {
+            throw new Exception(e);
+        } catch (JsonMappingException e) {
+            throw new Exception(e);
+        } catch (IOException e) {
+            throw new Exception(e);
+        }
+    }
+
+    public static <T> T unmarshal(InputStream is, Class<T> valueType) throws Exception {
+        try {
+            return OBJECT_MAPPER.readValue(is, valueType);
+        } catch (JsonParseException e) {
+            throw new Exception(e);
+        } catch (JsonMappingException e) {
+            throw new Exception(e);
+        } catch (IOException e) {
+            throw new Exception(e);
+        }
+    }
+
+    public static <T> T unmarshal(String str, Class<T> valueType) throws Exception {
+        try {
+            return OBJECT_MAPPER.readValue(str, valueType);
+        } catch (JsonParseException e) {
+            throw new Exception(e);
+        } catch (JsonMappingException e) {
+            throw new Exception(e);
+        } catch (IOException e) {
+            throw new Exception(e);
+        }
+    }
+
+    public static <T> T unmarshal(byte[] bytes, Class<T> valueType) throws Exception {
+        try {
+            if (bytes == null) {
+                bytes = new byte[0];
+            }
+            return OBJECT_MAPPER.readValue(bytes, 0, bytes.length, valueType);
+        } catch (JsonParseException e) {
+            throw new Exception(e);
+        } catch (JsonMappingException e) {
+            throw new Exception(e);
+        } catch (IOException e) {
+            throw new Exception(e);
+        }
+    }
+}
diff --git a/framework/src/main/java/com/yuanchu/limslaboratory/utils/JwtUtils.java b/framework/src/main/java/com/yuanchu/limslaboratory/utils/JwtUtils.java
new file mode 100644
index 0000000..34eaa8e
--- /dev/null
+++ b/framework/src/main/java/com/yuanchu/limslaboratory/utils/JwtUtils.java
@@ -0,0 +1,37 @@
+package com.yuanchu.limslaboratory.utils;
+
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTCreationException;
+
+import java.util.Date;
+
+public class JwtUtils {
+    // 杩囨湡鏃堕棿 2 灏忔椂
+//    private static final long EXPIRE_TIME = 2 * 60 * 60 * 1000;
+
+    private static final long EXPIRE_TIME = 10;
+    /**
+     * 鐢熸垚绛惧悕,鍑嗙‘鍦拌鏄敓鎴恡oken
+     * @param secret
+     * @return
+     */
+    public static String sign(String account, String secret){
+        try{
+            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
+            Algorithm algorithm = Algorithm.HMAC256(secret);
+            //闄勫甫username,nickname淇℃伅
+            return JWT.create()
+                    .withClaim("account",account)
+                    .withExpiresAt(date)
+                    .sign(algorithm);
+        } catch (JWTCreationException e){
+            e.printStackTrace();
+            return null;
+        } catch (Exception e){
+            e.printStackTrace();
+            return null;
+        }
+    }
+}
diff --git a/framework/src/main/java/com/yuanchu/limslaboratory/utils/MyUtils.java b/framework/src/main/java/com/yuanchu/limslaboratory/utils/MyUtils.java
new file mode 100644
index 0000000..dba8bec
--- /dev/null
+++ b/framework/src/main/java/com/yuanchu/limslaboratory/utils/MyUtils.java
@@ -0,0 +1,65 @@
+package com.yuanchu.limslaboratory.utils;
+
+import org.springframework.stereotype.Component;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Random;
+
+@Component
+public class MyUtils<T> {
+
+    /**
+     * 鑷畾涔夎皟璇曞伐鍏风被
+     * @return
+     */
+    public static void PrintLog(String str){
+        // 绫诲悕
+        String className = Thread.currentThread().getStackTrace()[2].getClassName();
+        // 鍑芥暟鍚�
+        String methodName = Thread.currentThread().getStackTrace()[2].getMethodName();
+        System.out.println("\033[1;94m" + className + "-->" + methodName + "-->"  + str + "\033[0m");
+    }
+
+    /**
+     * 鏃ユ湡宸ュ叿绫�
+     * @return
+     */
+    public static String MyDateFormat(){
+        //鑾峰彇鏃ユ湡
+        //瀵� import java.util.Date; 涓嬬殑鍖�
+        Date date = new Date();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+        return sdf.format(date);
+    }
+
+    /**
+     * 鑾峰彇闅忔満鍔犲瘑鐩�
+     * @param n 浣嶆暟
+     * @return 杩斿洖闅忔満鍔犲瘑鐩�
+     */
+    public static String getSalt(int n) {
+        char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#$%^&*()+-=/[];~.".toCharArray();
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < n; i++) {
+            char c = chars[new Random().nextInt(chars.length)];
+            sb.append(c);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 鑾峰彇闅忔満鍔犲瘑鐩�
+     * @param n 浣嶆暟
+     * @return 杩斿洖闅忔満鍊�
+     */
+    public static String getNumber(int n) {
+        char[] chars = "1234567890".toCharArray();
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < n; i++) {
+            char c = chars[new Random().nextInt(chars.length)];
+            sb.append(c);
+        }
+        return sb.toString();
+    }
+}
diff --git a/framework/src/main/java/com/yuanchu/limslaboratory/utils/RedisUtil.java b/framework/src/main/java/com/yuanchu/limslaboratory/utils/RedisUtil.java
new file mode 100644
index 0000000..cab09bf
--- /dev/null
+++ b/framework/src/main/java/com/yuanchu/limslaboratory/utils/RedisUtil.java
@@ -0,0 +1,622 @@
+package com.yuanchu.limslaboratory.utils;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class RedisUtil {
+    private static RedisTemplate<String, Object> redisTemplate;
+    public static RedisTemplate<String, Object> getRedisTemplate() {
+        return redisTemplate;
+    }
+    @Autowired
+    private RedisUtil(RedisConnectionFactory redisConnectionFactory){
+        // redisTemplate妯℃澘鍒濆鍖�
+        redisTemplate = new RedisTemplate<>();
+        redisTemplate.setConnectionFactory(redisConnectionFactory);
+
+        // 灏嗗璞″簭鍒楀寲
+        ObjectMapper om=new ObjectMapper();
+        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
+                ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
+
+        // String鐨勫簭鍒楀寲
+        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
+        // json搴忓垪鍖栭厤缃�
+        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer<>(Object.class);
+        jackson2JsonRedisSerializer.setObjectMapper(om);
+        //key閲囩敤String鐨勫簭鍒楀寲鏂瑰紡
+        redisTemplate.setKeySerializer(stringRedisSerializer);
+        //hash鐨刱ey涔熼噰鐢⊿tring 鐨勫簭鍒楀寲鏂瑰紡
+        redisTemplate.setHashKeySerializer(stringRedisSerializer);
+        //value鐨勫簭鍒楀寲鏂瑰紡閲囩敤jackson鐨勬柟寮�
+        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
+//        //hash鐨剉alue搴忓垪鍖栨柟寮忛噰鐢╦ackson
+        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
+        redisTemplate.afterPropertiesSet();
+    }
+
+    // =============================common============================
+    /**
+     * 鎸囧畾缂撳瓨澶辨晥鏃堕棿
+     * @param key  閿�
+     * @param time 鏃堕棿(绉�)
+     */
+    public static boolean expire(String key, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.expire(key, time, TimeUnit.SECONDS);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 鏍规嵁key 鑾峰彇杩囨湡鏃堕棿
+     * @param key 閿� 涓嶈兘涓簄ull
+     * @return 鏃堕棿(绉�) 杩斿洖0浠h〃涓烘案涔呮湁鏁�
+     */
+    public static long getExpire(String key) {
+        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+    }
+
+
+    /**
+     * 鍒ゆ柇key鏄惁瀛樺湪
+     * @param key 閿�
+     * @return true 瀛樺湪 false涓嶅瓨鍦�
+     */
+    public static boolean hasKey(String key) {
+        try {
+            return redisTemplate.hasKey(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+
+    /**
+     * 鍒犻櫎缂撳瓨
+     * @param key 鍙互浼犱竴涓�� 鎴栧涓�
+     */
+//    @SuppressWarnings("unchecked")
+    public static void del(String... key) {
+        if (key != null && key.length > 0) {
+            if (key.length == 1) {
+                redisTemplate.delete(key[0]);
+            } else {
+                redisTemplate.delete(Arrays.asList(key));
+//                redisTemplate.delete(CollectionUtils.arrayToList(key));
+            }
+        }
+    }
+
+    /**
+     * 鑾峰彇骞跺垹闄ょ紦瀛�
+     * @param key 閿�
+     * @return 鍊�
+     */
+    public static Object getAndDelete(String key) {
+        try{
+            return key == null ? null : get(key);
+        }finally {
+            del(key);
+        }
+    }
+
+    // ============================String=============================
+
+    /**
+     * 鏅�氱紦瀛樿幏鍙�
+     * @param key 閿�
+     * @return 鍊�
+     */
+    public static Object get(String key) {
+        return key == null ? null : redisTemplate.opsForValue().get(key);
+    }
+
+    /**
+     * 鏅�氱紦瀛樻斁鍏�
+     * @param key   閿�
+     * @param value 鍊�
+     * @return true鎴愬姛 false澶辫触
+     */
+
+    public static boolean set(String key, Object value) {
+        try {
+            redisTemplate.opsForValue().set(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+
+    /**
+     * 鏅�氱紦瀛樻斁鍏ュ苟璁剧疆鏃堕棿
+     * @param key   閿�
+     * @param value 鍊�
+     * @param time  鏃堕棿(绉�) time瑕佸ぇ浜�0 濡傛灉time灏忎簬绛変簬0 灏嗚缃棤闄愭湡
+     * @return true鎴愬姛 false 澶辫触
+     */
+
+    public static boolean set(String key, Object value, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.opsForValue().set(key, value, time, TimeUnit.MINUTES);
+            } else {
+                // 鍙慨鏀瑰弬鏁颁笉淇敼ttl
+                redisTemplate.opsForValue().set(key, value, 0);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+
+    /**
+     * 閫掑
+     * @param key   閿�
+     * @param delta 瑕佸鍔犲嚑(澶т簬0)
+     */
+    public static long incr(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("閫掑鍥犲瓙蹇呴』澶т簬0");
+        }
+        return redisTemplate.opsForValue().increment(key, delta);
+    }
+
+
+    /**
+     * 閫掑噺
+     * @param key   閿�
+     * @param delta 瑕佸噺灏戝嚑(灏忎簬0)
+     */
+    public static long decr(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("閫掑噺鍥犲瓙蹇呴』澶т簬0");
+        }
+        return redisTemplate.opsForValue().increment(key, -delta);
+    }
+
+
+    // ================================Map=================================
+
+    /**
+     * HashGet
+     * @param key  閿� 涓嶈兘涓簄ull
+     * @param item 椤� 涓嶈兘涓簄ull
+     */
+    public static Object hget(String key, String item) {
+        return redisTemplate.opsForHash().get(key, item);
+    }
+
+    /**
+     * 鑾峰彇hashKey瀵瑰簲鐨勬墍鏈夐敭鍊�
+     * @param key 閿�
+     * @return 瀵瑰簲鐨勫涓敭鍊�
+     */
+    public static Map<Object, Object> hmget(String key) {
+        return redisTemplate.opsForHash().entries(key);
+    }
+
+    /**
+     * HashSet
+     * @param key 閿�
+     * @param map 瀵瑰簲澶氫釜閿��
+     */
+    public static boolean hmset(String key, Map<String, Object> map) {
+        try {
+            redisTemplate.opsForHash().putAll(key, map);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+
+    /**
+     * HashSet 骞惰缃椂闂�
+     * @param key  閿�
+     * @param map  瀵瑰簲澶氫釜閿��
+     * @param time 鏃堕棿(绉�)
+     * @return true鎴愬姛 false澶辫触
+     */
+    public static boolean hmset(String key, Map<String, Object> map, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.opsForHash().putAll(key, map);
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+
+    /**
+     * 鍚戜竴寮爃ash琛ㄤ腑鏀惧叆鏁版嵁,濡傛灉涓嶅瓨鍦ㄥ皢鍒涘缓
+     *
+     * @param key   閿�
+     * @param item  椤�
+     * @param value 鍊�
+     * @return true 鎴愬姛 false澶辫触
+     */
+    public static boolean hset(String key, String item, Object value) {
+        try {
+            redisTemplate.opsForHash().put(key, item, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 鍚戜竴寮爃ash琛ㄤ腑鏀惧叆鏁版嵁,濡傛灉涓嶅瓨鍦ㄥ皢鍒涘缓
+     *
+     * @param key   閿�
+     * @param item  椤�
+     * @param value 鍊�
+     * @param time  鏃堕棿(绉�) 娉ㄦ剰:濡傛灉宸插瓨鍦ㄧ殑hash琛ㄦ湁鏃堕棿,杩欓噷灏嗕細鏇挎崲鍘熸湁鐨勬椂闂�
+     * @return true 鎴愬姛 false澶辫触
+     */
+    public static boolean hset(String key, String item, Object value, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.opsForHash().put(key, item, value);
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 鍒犻櫎hash琛ㄤ腑鐨勫��
+     *
+     * @param key  閿� 涓嶈兘涓簄ull
+     * @param item 椤� 鍙互浣垮涓� 涓嶈兘涓簄ull
+     */
+    public static void hdel(String key, Object... item) {
+        redisTemplate.opsForHash().delete(key, item);
+    }
+
+
+    /**
+     * 鍒ゆ柇hash琛ㄤ腑鏄惁鏈夎椤圭殑鍊�
+     *
+     * @param key  閿� 涓嶈兘涓簄ull
+     * @param item 椤� 涓嶈兘涓簄ull
+     * @return true 瀛樺湪 false涓嶅瓨鍦�
+     */
+    public static boolean hHasKey(String key, String item) {
+        return redisTemplate.opsForHash().hasKey(key, item);
+    }
+
+
+    /**
+     * hash閫掑 濡傛灉涓嶅瓨鍦�,灏变細鍒涘缓涓�涓� 骞舵妸鏂板鍚庣殑鍊艰繑鍥�
+     *
+     * @param key  閿�
+     * @param item 椤�
+     * @param by   瑕佸鍔犲嚑(澶т簬0)
+     */
+    public static double hincr(String key, String item, double by) {
+        return redisTemplate.opsForHash().increment(key, item, by);
+    }
+
+
+    /**
+     * hash閫掑噺
+     *
+     * @param key  閿�
+     * @param item 椤�
+     * @param by   瑕佸噺灏戣(灏忎簬0)
+     */
+    public static double hdecr(String key, String item, double by) {
+        return redisTemplate.opsForHash().increment(key, item, -by);
+    }
+
+
+    // ============================set=============================
+
+    /**
+     * 鏍规嵁key鑾峰彇Set涓殑鎵�鏈夊��
+     * @param key 閿�
+     */
+    public static Set<Object> sGet(String key) {
+        try {
+            return redisTemplate.opsForSet().members(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+
+    /**
+     * 鏍规嵁value浠庝竴涓猻et涓煡璇�,鏄惁瀛樺湪
+     *
+     * @param key   閿�
+     * @param value 鍊�
+     * @return true 瀛樺湪 false涓嶅瓨鍦�
+     */
+    public static boolean sHasKey(String key, Object value) {
+        try {
+            return redisTemplate.opsForSet().isMember(key, value);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+
+    /**
+     * 灏嗘暟鎹斁鍏et缂撳瓨
+     *
+     * @param key    閿�
+     * @param values 鍊� 鍙互鏄涓�
+     * @return 鎴愬姛涓暟
+     */
+    public static long sSet(String key, Object... values) {
+        try {
+            return redisTemplate.opsForSet().add(key, values);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+
+    /**
+     * 灏唖et鏁版嵁鏀惧叆缂撳瓨
+     *
+     * @param key    閿�
+     * @param time   鏃堕棿(绉�)
+     * @param values 鍊� 鍙互鏄涓�
+     * @return 鎴愬姛涓暟
+     */
+    public static long sSetAndTime(String key, long time, Object... values) {
+        try {
+            Long count = (long)values.length;
+            if (time > 0) {
+                count = redisTemplate.opsForSet().add(key, values);
+                expire(key, time);
+            }
+            return count;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+
+    /**
+     * 鑾峰彇set缂撳瓨鐨勯暱搴�
+     *
+     * @param key 閿�
+     */
+    public static long sGetSetSize(String key) {
+        try {
+            return redisTemplate.opsForSet().size(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+
+    /**
+     * 绉婚櫎鍊间负value鐨�
+     *
+     * @param key    閿�
+     * @param values 鍊� 鍙互鏄涓�
+     * @return 绉婚櫎鐨勪釜鏁�
+     */
+
+    public static long setRemove(String key, Object... values) {
+        try {
+            return redisTemplate.opsForSet().remove(key, values);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    // ===============================list=================================
+
+    /**
+     * 鑾峰彇list缂撳瓨鐨勫唴瀹�
+     *
+     * @param key   閿�
+     * @param start 寮�濮�
+     * @param end   缁撴潫 0 鍒� -1浠h〃鎵�鏈夊��
+     */
+    public static List<Object> lGet(String key, long start, long end) {
+        try {
+            return redisTemplate.opsForList().range(key, start, end);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+
+    /**
+     * 鑾峰彇list缂撳瓨鐨勯暱搴�
+     *
+     * @param key 閿�
+     */
+    public static long lGetListSize(String key) {
+        try {
+            return redisTemplate.opsForList().size(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+
+    /**
+     * 閫氳繃绱㈠紩 鑾峰彇list涓殑鍊�
+     *
+     * @param key   閿�
+     * @param index 绱㈠紩 index>=0鏃讹紝 0 琛ㄥご锛�1 绗簩涓厓绱狅紝渚濇绫绘帹锛沬ndex<0鏃讹紝-1锛岃〃灏撅紝-2鍊掓暟绗簩涓厓绱狅紝渚濇绫绘帹
+     */
+    public static Object lGetIndex(String key, long index) {
+        try {
+            return redisTemplate.opsForList().index(key, index);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+
+    /**
+     * 灏唋ist鏀惧叆缂撳瓨
+     *
+     * @param key   閿�
+     * @param value 鍊�
+     */
+    public static boolean lSet(String key, Object value) {
+        try {
+            redisTemplate.opsForList().rightPush(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+
+    /**
+     * 灏唋ist鏀惧叆缂撳瓨
+     * @param key   閿�
+     * @param value 鍊�
+     * @param time  鏃堕棿(绉�)
+     */
+    public static boolean lSet(String key, Object value, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.opsForList().rightPush(key, value);
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+
+    }
+
+
+    /**
+     * 灏唋ist鏀惧叆缂撳瓨
+     *
+     * @param key   閿�
+     * @param value 鍊�
+     * @return true 瀛樻斁鎴愬姛 false瀛樻斁澶辫触
+     */
+    public static boolean lSet(String key, List<Object> value) {
+        try {
+            redisTemplate.opsForList().rightPushAll(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+
+    }
+
+
+    /**
+     * 灏唋ist鏀惧叆缂撳瓨
+     *
+     * @param key   閿�
+     * @param value 鍊�
+     * @param time  鏃堕棿(绉�)
+     * @return true 瀛樻斁鎴愬姛 false瀛樻斁澶辫触
+     */
+    public static boolean lSet(String key, List<Object> value, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.opsForList().rightPushAll(key, value);
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+
+    /**
+     * 鏍规嵁绱㈠紩淇敼list涓殑鏌愭潯鏁版嵁
+     *
+     * @param key   閿�
+     * @param index 绱㈠紩
+     * @param value 鍊�
+     * @return true 瀛樻斁鎴愬姛 false瀛樻斁澶辫触
+     */
+
+    public static boolean lUpdateIndex(String key, long index, Object value) {
+        try {
+            redisTemplate.opsForList().set(key, index, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+
+    /**
+     * 绉婚櫎N涓�间负value
+     *
+     * @param key   閿�
+     * @param count 绉婚櫎澶氬皯涓�
+     * @param value 鍊�
+     * @return 绉婚櫎鐨勪釜鏁�
+     */
+
+    public static long lRemove(String key, long count, Object value) {
+        try {
+            return redisTemplate.opsForList().remove(key, count, value);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+}
+
diff --git a/framework/src/main/java/com/yuanchu/limslaboratory/utils/SpringUtils.java b/framework/src/main/java/com/yuanchu/limslaboratory/utils/SpringUtils.java
new file mode 100644
index 0000000..f611767
--- /dev/null
+++ b/framework/src/main/java/com/yuanchu/limslaboratory/utils/SpringUtils.java
@@ -0,0 +1,51 @@
+package com.yuanchu.limslaboratory.utils;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SpringUtils implements ApplicationContextAware {
+    private static ApplicationContext context;
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        context = applicationContext;
+    }
+
+    public static void set(ApplicationContext applicationContext) {
+        context = applicationContext;
+    }
+
+    /**
+     * 閫氳繃瀛楄妭鐮佽幏鍙�
+     * @param beanClass
+     * @param <T>
+     * @return
+     */
+    public static <T> T getBean(Class<T> beanClass) {
+        return context.getBean(beanClass);
+    }
+
+    /**
+     * 閫氳繃BeanName鑾峰彇
+     * @param beanName
+     * @param <T>
+     * @return
+     */
+    public static <T> T getBean(String beanName) {
+        return (T) context.getBean(beanName);
+    }
+
+    /**
+     * 閫氳繃beanName鍜屽瓧鑺傜爜鑾峰彇
+     * @param name
+     * @param beanClass
+     * @param <T>
+     * @return
+     */
+    public static <T> T getBean(String name, Class<T> beanClass) {
+        return context.getBean(name, beanClass);
+    }
+}
diff --git a/framework/src/main/java/com/yuanchu/limslaboratory/vo/Result.java b/framework/src/main/java/com/yuanchu/limslaboratory/vo/Result.java
new file mode 100644
index 0000000..ab0385c
--- /dev/null
+++ b/framework/src/main/java/com/yuanchu/limslaboratory/vo/Result.java
@@ -0,0 +1,53 @@
+package com.yuanchu.limslaboratory.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Result<T> {
+
+    @ApiModelProperty(value = "鍝嶅簲鐮侊細200鎴愬姛锛�201澶辫触")
+    private int code;
+
+    @ApiModelProperty(value = "鍝嶅簲娑堟伅")
+    private String message;
+
+    @ApiModelProperty(value = "鍝嶅簲鍙傛暟")
+    private T data;
+
+    public static <T> Result<T> success(){
+        return new Result<>(200, "success",null);
+    }
+
+    public static <T> Result<T> success(String message){
+        return new Result<>(200, message,null);
+    }
+
+    public static <T> Result<T> success(T data){
+        return new Result<>(200, "success",data);
+    }
+
+    public static <T> Result<T> success(String message, T data){
+        return new Result<>(200, message,data);
+    }
+
+    public static <T> Result<T> fail(){
+        return new Result<>(201, "fail", null);
+    }
+
+    public static <T> Result<T> fail(String message){
+        return new Result<>(201, message, null);
+    }
+
+    public static <T> Result<T> fail(Integer code){
+        return new Result<>(code, "fail", null);
+    }
+
+    public static <T> Result<T> fail(Integer code, String message){
+        return new Result<>(code, message, null);
+    }
+}
diff --git a/sys/src/main/java/com/yuanchu/limslaboratory/SysApplication.java b/sys/src/main/java/com/yuanchu/limslaboratory/SysApplication.java
new file mode 100644
index 0000000..6515734
--- /dev/null
+++ b/sys/src/main/java/com/yuanchu/limslaboratory/SysApplication.java
@@ -0,0 +1,13 @@
+package com.yuanchu.limslaboratory;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SysApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(SysApplication.class, args);
+    }
+
+}
diff --git a/sys/src/test/java/com/yuanchu/limslaboratory/CodeGenerator.java b/sys/src/test/java/com/yuanchu/limslaboratory/CodeGenerator.java
new file mode 100644
index 0000000..063777c
--- /dev/null
+++ b/sys/src/test/java/com/yuanchu/limslaboratory/CodeGenerator.java
@@ -0,0 +1,129 @@
+package com.yuanchu.limslaboratory;
+
+import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.generator.AutoGenerator;
+import com.baomidou.mybatisplus.generator.InjectionConfig;
+import com.baomidou.mybatisplus.generator.config.*;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+// 婕旂ず渚嬪瓙锛屾墽琛� main 鏂规硶鎺у埗鍙拌緭鍏ユā鍧楄〃鍚嶅洖杞﹁嚜鍔ㄧ敓鎴愬搴旈」鐩洰褰曚腑
+public class CodeGenerator {
+
+    public static String database_url = "jdbc:mysql://localhost:3306/lims_manage?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai";
+    public static String database_driver_name = "com.mysql.cj.jdbc.Driver";
+    public static String database_username = "root";
+    public static String database_password= "123456";
+    public static String author = "姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃";
+    public static String model_name = "/user-server"; // 濡傛灉涓哄垎甯冨紡濉瓙妯″潡鍚嶇О锛屽鏋滀笉鏄垎甯冨紡涓虹┖鍗冲彲
+    public static String setParent = "com.yunchu.limslaboratory"; // 鍖呰矾寰�
+    public static Boolean Override = true; // 鏄惁瑕嗙洊鍘熸潵鐨勬枃浠讹紵
+
+    public static void main(String[] args) {
+        // 浠g爜鐢熸垚鍣�
+        AutoGenerator mpg = new AutoGenerator();
+
+        String projectPath = System.getProperty("user.dir");
+        System.out.println(projectPath+"===================");
+
+        GlobalConfig gc = new GlobalConfig() // 鍏ㄥ眬閰嶇疆
+                .setOutputDir(projectPath + model_name + "/src/main/java") // 杈撳嚭璺緞
+                .setAuthor(author) // 浣滆�呮敞閲�
+                .setOpen(false) // 鏄惁鎵撳紑
+                .setSwagger2(true) //瀹炰綋灞炴�� Swagger2 娉ㄨВ
+                .setServiceName("%sService") // 璁剧疆serviceName鐨勫悕绉板幓澶у啓I
+                .setFileOverride(Override);// 鏄惁瑕嗙洊宸茬敓鎴愭枃浠�
+        mpg.setGlobalConfig(gc);
+
+        // 鏁版嵁婧愰厤缃� 鏁版嵁搴撳悕 璐﹀彿瀵嗙爜
+        DataSourceConfig dsc = new DataSourceConfig()
+                .setUrl(database_url)
+                .setDriverName(database_driver_name)
+                .setUsername(database_username)
+                .setPassword(database_password);
+        mpg.setDataSource(dsc);
+
+
+        // 鍖呴厤缃�
+        PackageConfig pc = new PackageConfig()
+                .setModuleName(null)
+                .setParent(setParent)
+                .setEntity("pojo");// 鍖呰矾寰�
+        mpg.setPackageInfo(pc);
+
+        // 鑷畾涔夐厤缃�
+        InjectionConfig cfg = new InjectionConfig() {
+            @Override
+            public void initMap() {
+                // to do nothing
+            }
+        };
+
+        // 濡傛灉妯℃澘寮曟搸鏄� freemarker
+        String templatePath = "/templates/mapper.xml.ftl";
+        // 濡傛灉妯℃澘寮曟搸鏄� velocity
+        // String templatePath = "/templates/mapper.xml.vm";
+
+        // 鑷畾涔夎緭鍑洪厤缃�
+        List<FileOutConfig> focList = new ArrayList<>();
+        // 鑷畾涔夐厤缃細琚紭鍏堣緭鍑�
+        focList.add(new FileOutConfig(templatePath) {
+            @Override
+            public String outputFile(TableInfo tableInfo) {
+                // 鑷畾涔夎緭鍑烘枃浠跺悕 锛� 濡傛灉浣� Entity 璁剧疆浜嗗墠鍚庣紑銆佹澶勬敞鎰� xml 鐨勫悕绉颁細璺熺潃鍙戠敓鍙樺寲锛�
+                return projectPath + model_name + "/src/main/resources/mapper/"
+                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
+            }
+        });
+
+        cfg.setFileOutConfigList(focList);
+        mpg.setCfg(cfg);
+
+        // 閰嶇疆妯℃澘
+        TemplateConfig templateConfig = new TemplateConfig()
+                .setXml(null);
+
+        mpg.setTemplate(templateConfig);
+
+        // 绛栫暐閰嶇疆
+        StrategyConfig strategy = new StrategyConfig()
+                .setNaming(NamingStrategy.underline_to_camel)
+                .setColumnNaming(NamingStrategy.underline_to_camel)
+                .setEntityLombokModel(true)
+                .setRestControllerStyle(true)
+                .setInclude(scanner("琛ㄥ悕锛屽涓┖鏍煎垎鍓�").split(" "))
+                .setControllerMappingHyphenStyle(true)
+                .setTablePrefix("m_");
+        mpg.setStrategy(strategy);
+        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
+        //濡傛灉涓嶈皟鐢ㄨ鏂规硶銆佸氨浼氫娇鐢∕yBatis-Plus榛樿鐨勬枃浠剁敓鎴愯矾寰勫拰鍖呰矾寰勭敓鎴愭枃浠躲�佷絾鍙互浣跨敤涓婇潰鐨凱ackageConfig鍋氫竴浜涚畝鍗曠殑閰嶇疆
+        mpg.execute();
+    }
+
+    /**
+     * <p>
+     * 璇诲彇鎺у埗鍙板唴瀹�
+     * </p>
+     */
+    public static String scanner(String tip) {
+        Scanner scanner = new Scanner(System.in);
+        StringBuilder help = new StringBuilder();
+        help.append("璇疯緭鍏�" + tip + "锛�");
+        System.out.println(help.toString());
+        if (scanner.hasNext()) {
+            String ipt = scanner.next();
+
+            if (StringUtils.isNotBlank(ipt)) {
+                return ipt;
+            }
+        }
+        throw new MybatisPlusException("璇疯緭鍏ユ纭殑" + tip + "锛�");
+    }
+}
diff --git a/sys/src/test/java/com/yuanchu/limslaboratory/SysApplicationTests.java b/sys/src/test/java/com/yuanchu/limslaboratory/SysApplicationTests.java
new file mode 100644
index 0000000..9c10eef
--- /dev/null
+++ b/sys/src/test/java/com/yuanchu/limslaboratory/SysApplicationTests.java
@@ -0,0 +1,16 @@
+package com.yuanchu.limslaboratory;
+
+import com.yuanchu.limslaboratory.utils.MyUtils;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class SysApplicationTests {
+
+    @Test
+    void contextLoads() {
+        String number = MyUtils.getNumber(6);
+        System.out.println(number);
+    }
+
+}
diff --git a/user-server/src/main/java/com/yuanchu/limslaboratory/clients/UserClient.java b/user-server/src/main/java/com/yuanchu/limslaboratory/clients/UserClient.java
new file mode 100644
index 0000000..da0c9fa
--- /dev/null
+++ b/user-server/src/main/java/com/yuanchu/limslaboratory/clients/UserClient.java
@@ -0,0 +1,19 @@
+package com.yuanchu.limslaboratory.clients;
+
+import com.yuanchu.limslaboratory.vo.Result;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.Map;
+
+@FeignClient(value = "userservice", url = "localhost:6789")
+public interface UserClient {
+
+    @PostMapping("/business/login")
+    Result<?> BusynessUserLogin(@RequestBody Map<String, Object> mapData);
+
+    @PostMapping("/business/code")
+    Result<?> BusynessUserLoginToken(@RequestParam("code") String code);
+}
diff --git a/user-server/src/main/java/com/yuanchu/limslaboratory/clients/UserLoginUtils.java b/user-server/src/main/java/com/yuanchu/limslaboratory/clients/UserLoginUtils.java
new file mode 100644
index 0000000..04dc927
--- /dev/null
+++ b/user-server/src/main/java/com/yuanchu/limslaboratory/clients/UserLoginUtils.java
@@ -0,0 +1,73 @@
+package com.yuanchu.limslaboratory.clients;
+
+import com.yuanchu.limslaboratory.vo.Result;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class UserLoginUtils {
+
+    @Resource
+    private UserClient userClient;
+
+    @Value("${login.userID}")
+    private String LoginUserID;
+
+    @Value("${login.secret}")
+    private String LoginSecret;
+//    public Result<Map<String, Object>> LoginExamine(User user){
+//        Map<String, Object> mapData = new HashMap<>();
+//        mapData.put("LoginUserID", LoginUserID);
+//        mapData.put("LoginSecret", LoginSecret);
+//        Result<?> code = userClient.BusynessUserLogin(mapData);
+//        if (code.getCode() == 200){
+//            Result<?> result = userClient.BusynessUserLoginToken(code.getData().toString());
+//            if (result.getCode() == 200){
+//                Map data = (Map) result.getData();
+//                String token = data.get("token").toString();
+//                data.remove("token");
+//                user.setMap(data);
+//                //瀛樺叆redis,浜屼釜灏忔椂鍚庡垹闄�
+//                RedisUtil.set(token, user, 2);
+//                // 灏嗙鍙戠殑 JWT token 杩斿洖缁欏墠绔�
+//                HashMap<String, Object> map = new HashMap<>();
+//                String refresh = JwtUtils.sign(user.getAccount());
+//                map.put("token", token);
+//                map.put("refresh", refresh);
+//                RedisUtil.set(user.getAccount(), map, 168);
+//                return Result.success(map);
+//            } else {
+//                return Result.fail(result.getMessage());
+//            }
+//        } else {
+//            return Result.fail(code.getMessage());
+//        }
+//    }
+
+    public Result<Map<String, Object>> LoginExamine(){
+        Map<String, Object> mapData = new HashMap<>();
+        mapData.put("LoginUserID", LoginUserID);
+        mapData.put("LoginSecret", LoginSecret);
+        Result<?> code = userClient.BusynessUserLogin(mapData);
+        if (code.getCode() == 200){
+            Result<?> result = userClient.BusynessUserLoginToken(code.getData().toString());
+            if (result.getCode() == 200){
+                Map data = (Map) result.getData();
+                String token = data.get("token").toString();
+                data.remove("token");
+                // 灏嗙鍙戠殑 JWT token 杩斿洖缁欏墠绔�
+                HashMap<String, Object> map = new HashMap<>();
+                map.put("token", token);
+                return Result.success(map);
+            } else {
+                return Result.fail(result.getMessage());
+            }
+        } else {
+            return Result.fail(code.getMessage());
+        }
+    }
+}
diff --git a/user-server/src/main/java/com/yuanchu/limslaboratory/config/FeignConfig.java b/user-server/src/main/java/com/yuanchu/limslaboratory/config/FeignConfig.java
new file mode 100644
index 0000000..c72c031
--- /dev/null
+++ b/user-server/src/main/java/com/yuanchu/limslaboratory/config/FeignConfig.java
@@ -0,0 +1,37 @@
+package com.yuanchu.limslaboratory.config;
+
+
+import feign.Feign;
+import okhttp3.OkHttpClient;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.cloud.commons.httpclient.OkHttpClientFactory;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.cloud.openfeign.FeignAutoConfiguration;
+import org.springframework.cloud.openfeign.support.FeignHttpClientProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.concurrent.TimeUnit;
+
+@EnableFeignClients("com.yuanchu.limslaboratory.clients") // 鎵弿feign鎺ュ彛鎵�鍦ㄥ寘 閲嶈
+@Configuration
+@ConditionalOnClass(Feign.class)
+@AutoConfigureBefore(FeignAutoConfiguration.class)
+public class FeignConfig {
+
+    private OkHttpClient okHttpClient;
+
+
+    //娉ㄥ叆okhttp
+    @Bean
+    public OkHttpClient okHttpClient(OkHttpClientFactory okHttpClientFactory,
+                                             FeignHttpClientProperties httpClientProperties) {
+        this.okHttpClient = okHttpClientFactory.createBuilder(httpClientProperties.isDisableSslValidation()).connectTimeout(httpClientProperties.getConnectionTimeout(),TimeUnit.SECONDS)
+                .followRedirects(httpClientProperties.isFollowRedirects())
+                .build();
+        return this.okHttpClient;
+    }
+
+}
+
diff --git a/user-server/src/main/java/com/yuanchu/limslaboratory/controller/AdminController.java b/user-server/src/main/java/com/yuanchu/limslaboratory/controller/AdminController.java
new file mode 100644
index 0000000..2f93b30
--- /dev/null
+++ b/user-server/src/main/java/com/yuanchu/limslaboratory/controller/AdminController.java
@@ -0,0 +1,70 @@
+package com.yuanchu.limslaboratory.controller;
+
+
+import com.yuanchu.limslaboratory.clients.UserLoginUtils;
+import com.yuanchu.limslaboratory.pojo.Admin;
+import com.yuanchu.limslaboratory.service.AdminService;
+import com.yuanchu.limslaboratory.utils.SpringUtils;
+import com.yuanchu.limslaboratory.vo.Result;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ *  鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2023-07-04
+ */
+@Api(tags = "绠$悊鍛樻搷浣滄帴鍙�")
+@RestController
+@RequestMapping("/admin")
+public class AdminController {
+
+    @Autowired
+    private AdminService service;
+
+    @ApiOperation("Post鎺ュ彛")
+    @PostMapping("/post")
+    public Result<Map<String, Object>> post(Admin admin) {
+        UserLoginUtils bean = SpringUtils.getBean(UserLoginUtils.class);
+        return bean.LoginExamine();
+    }
+
+    @ApiOperation("鍒犻櫎鎺ュ彛")
+    @ApiImplicitParams(value = {
+            @ApiImplicitParam(name = "id", value = "闇�瑕佸垹闄ょ殑ID", dataTypeClass = String.class, required = true)
+    })
+    @PostMapping("/delete")
+    public Result<?> delete(Integer id) {
+        service.removeById(id);
+        return Result.success("鐧诲綍鎴愬姛");
+    }
+
+    @ApiOperation("鏌ヨ鎺ュ彛")
+    @GetMapping("/get")
+    public Result<?> get() {
+        List<Admin> list = service.list();
+        return Result.success(list);
+    }
+
+    @GetMapping("/鏇存柊鎺ュ彛")
+    @ApiOperation("Crunchy")
+    @ApiImplicitParams(value = {
+            @ApiImplicitParam(name = "id", value = "闇�瑕佺殑ID", dataTypeClass = String.class, required = true)
+    })
+    public Result<?> put(String id) {
+        Admin systest2 = service.getById(id);
+        systest2.setId(1);
+        service.updateById(systest2);
+        return Result.success();
+    }
+}
diff --git a/user-server/src/main/java/com/yuanchu/limslaboratory/mapper/AdminMapper.java b/user-server/src/main/java/com/yuanchu/limslaboratory/mapper/AdminMapper.java
new file mode 100644
index 0000000..1b0c719
--- /dev/null
+++ b/user-server/src/main/java/com/yuanchu/limslaboratory/mapper/AdminMapper.java
@@ -0,0 +1,16 @@
+package com.yuanchu.limslaboratory.mapper;
+
+import com.yuanchu.limslaboratory.pojo.Admin;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ *  Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2023-07-04
+ */
+public interface AdminMapper extends BaseMapper<Admin> {
+
+}
diff --git a/user-server/src/main/java/com/yuanchu/limslaboratory/pojo/Admin.java b/user-server/src/main/java/com/yuanchu/limslaboratory/pojo/Admin.java
new file mode 100644
index 0000000..53db2ca
--- /dev/null
+++ b/user-server/src/main/java/com/yuanchu/limslaboratory/pojo/Admin.java
@@ -0,0 +1,52 @@
+package com.yuanchu.limslaboratory.pojo;
+
+import com.baomidou.mybatisplus.annotation.*;
+
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2023-07-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value="Admin瀵硅薄", description="")
+public class Admin implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "涓婚敭ID", hidden = true)
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty(value = "鍒涘缓鏃堕棿", hidden = true)
+    @TableField(fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm", timezone="GMT+8") // 鍚庡彴缁欏墠绔仛鏃堕棿鏍煎紡鍖�
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "鏇存柊鏃堕棿", hidden = true)
+    @TableField(fill = FieldFill.INSERT_UPDATE, update = "now()")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm", timezone="GMT+8") // 鍚庡彴缁欏墠绔仛鏃堕棿鏍煎紡鍖�
+    private LocalDateTime updateTime;
+
+    @TableLogic(value = "0", delval = "1")
+    @ApiModelProperty(value = "閫昏緫鍒犻櫎", hidden = true)
+    private Integer isDelete;
+
+    @ApiModelProperty(value = "涔愯閿�", hidden = true)
+//    @Version
+    private Integer version;
+
+
+}
diff --git a/user-server/src/main/java/com/yuanchu/limslaboratory/service/AdminService.java b/user-server/src/main/java/com/yuanchu/limslaboratory/service/AdminService.java
new file mode 100644
index 0000000..c6e61a6
--- /dev/null
+++ b/user-server/src/main/java/com/yuanchu/limslaboratory/service/AdminService.java
@@ -0,0 +1,16 @@
+package com.yuanchu.limslaboratory.service;
+
+import com.yuanchu.limslaboratory.pojo.Admin;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ *  鏈嶅姟绫�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2023-07-04
+ */
+public interface AdminService extends IService<Admin> {
+
+}
diff --git a/user-server/src/main/java/com/yuanchu/limslaboratory/service/impl/AdminServiceImpl.java b/user-server/src/main/java/com/yuanchu/limslaboratory/service/impl/AdminServiceImpl.java
new file mode 100644
index 0000000..db1d7df
--- /dev/null
+++ b/user-server/src/main/java/com/yuanchu/limslaboratory/service/impl/AdminServiceImpl.java
@@ -0,0 +1,20 @@
+package com.yuanchu.limslaboratory.service.impl;
+
+import com.yuanchu.limslaboratory.pojo.Admin;
+import com.yuanchu.limslaboratory.mapper.AdminMapper;
+import com.yuanchu.limslaboratory.service.AdminService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author 姹熻嫃榈烽洀缃戠粶绉戞妧鏈夐檺鍏徃
+ * @since 2023-07-04
+ */
+@Service
+public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements AdminService {
+
+}

--
Gitblit v1.9.3