SpringBoot объединяет проект строительных лесов jwt и mybatis-plus.

Архитектура

Недавно я получил проект строительных лесов для компании, и я планирую использовать его в фоновой разработке в будущем. Пожалуйста, поставьте звездочку~

нажмитеПерейти к адресу github

Обзор

Volcano — это простой скаффолд, основанный на фоновой разработке Springboot. Его можно использовать как отдельный проект или как узел микросервисов для быстрой разработки и развертывания.

Список изменений

14.11.2019 Добавить решение для исключения чванства

Структура проекта

Родительский класс javasea-volcano, используемый для управления версиями springcloud и springboot, плагина maven, единого управления складом и т. д.

|--javasea-volcano-base: тестовые классы и связанные с ними бизнес-конфигурации, зависимостиcommonДля компонентов в проекте можно добавить бизнес-код на основе проекта во время разработки.

|--javasea-volcano-common: Общие компоненты и инструменты

Среда проекта

промежуточное ПО Версия Примечание
JDK 1.8+ JDK1.8 и выше
MySQL 5.6+ 5.6 и выше
Redis 3.2+

основные навыки

Справочный пакетcom.zhirui.lmwy.wms.demoконфигурация под

проверка параметров

JSR-проверка

spring-boot-starter-webПроверка JSR303 встроена по умолчанию, и вам нужно только напрямую использовать проверку аннотаций.

Эталонный тестовый класс: com.zhirui.lmwy.wms.demo.web.controller.TestCheckParamController

Ручная проверка

AssertКласс определяет способ быстрого утверждения, когда условие не выполняется, что можно использовать в параметрах проверки.

Вы также можете использовать Spring Assert для проверки

//第一个参数为false则抛出IllegalArgumentException异常
Assert.isTrue(concurrentConsumers > 0, "'concurrentConsumers' value must be at least 1 (one)");
Assert.isTrue(!this.exclusive || concurrentConsumers == 1,"When the consumer is exclusive, the concurrency must be 1");

Дополнительно можно также использовать для проверки

ZOrder order = this.getOrderByOrderNum(orderNum);
Optional.ofNullable(order).filter(o -> {
    return null != o && (0 == o.getStatus() || 3 == o.getStatus() || 9 == o.getStatus());
}).orElseThrow(() -> new ParamException("获取数据异常,订单号有误或者订单状态异常!"));

Проверка параметров также может быть выполнена с помощью класса предварительных условий Guava. При необходимости, пожалуйста, Baidu.

преобразование параметров

Эталонный тестовый класс: TestDateConverterAndJson

URL-метод для передачи значения для внутренней конверсии

Существует три способа передачи параметров из URL в серверную часть:

@GetMapping("testDateConverter")
public Student testDateConverter(@RequestParam Student student){...}

@GetMapping("testDateConverter")
public Student testDateConverter(Student student){...}

@GetMapping("testDateConverter/{id}")
public Student testDateConverter(@PathVariable Integer id){...}

com.zhirui.lmwy.common.converterМногие классы преобразования определены в пакете:

  • StringToDateConverter

    Если атрибутом сущности является Дата, преобразуйте тип String в Date с помощью этого преобразователя. Аннотации к свойствам эффекта и даты@DatetimeFormatтакой же. Но когда конвертер включен, аннотация к свойству сущности@DatetimeFormatНе нужно вступать в силу.

  • StringToDoubleConverter

    Если атрибут сущности имеет значение Double, преобразуйте тип String в Double с помощью этого преобразователя.

  • StringToIntegerConverter

    Если свойство сущности имеет значение Integer, преобразуйте тип String в Integer с помощью этого преобразователя.

Метод тела запроса для передачи значения в бэкэнд-конверсию

Метод тела запроса для передачи параметров серверной части включает следующие методы:

@PostMapping("testDateConverter2")
public Student testDateConverter2(@RequestBody Student student){...}

com.zhirui.lmwy.common.json.jacksonМетоды сериализации и десериализации JSON определены в пакете:

  • Класс сериализации в пакете десериализатора

    Когда @RequestBody получает параметры, он вызывает序列化类Преобразование JSON в параметры объекта.

  • Класс сериализатора в пакете сериализатора

    Используется для передачи значений из бэкенда во фронтенд.

Передача значений из бэкенда во фронтенд

com.zhirui.lmwy.common.json.jackson.serializerКласс сериализации определяется в пакете.

Добавьте аннотацию @ResponseBody или @RestController к классу Controller, тогда серверная часть для передачи значения во внешний интерфейс будет JSON.

Если возвращаемое значение является объектом или коллекцией, класс сериализации будет использоваться для преобразования типа параметра.

В следующих подразделах две даты атрибута в Student преобразуются в формат «гггг-мм-дд чч:мм:сс», определенный сериализатором.

序列化类``JacksonDateSerializerЭффект эквивалентен добавлению к атрибуту@JsonFormat(pattern="yyyy-MM-dd"), реализация преобразует тип Date в String, но добавляетJacksonDateSerializerЗадний@JsonFormat(pattern="yyyy-MM-dd")недействителен.

    @PostMapping("testDateConverter2")
    public Student testDateConverter2(@RequestBody Student student){
        System.out.println(student);
        Student s = new Student();
        s.setBirth(new Date());
        s.setCreateTime(LocalDateTime.now());
        return s;
    }

Обработка исключений

существуетcom.zhirui.lmwy.common.exception.implОпределены три типа исключений:

BusinessException: 通用业务异常
ParamException:参数校验异常
AuthenticationException:认证失败异常

ExceptionsКласс определяет некоторые общие методы для быстрого создания исключений. Пожалуйста, не используйте его, когда вам нужно создавать исключения.throw new XXXException(), но использоватьExceptionsметоды класса для работы.

Определен глобальный обработчик исключений.GlobalExceptionHandlerРазличные исключения могут быть обработаны, пожалуйста, не в контроллере и не в сервисеtry..catch.

обработка возвращаемого значения

Возврат к переднему концу контроллера используетсяResultModelИнкапсулированный класс, который содержитcode,msg,dataЖдать поля.

РеальзованныйМодель в различных сценариях возвращается:

    //插入后返回方式, msg:插入成功;插入失败
    public ResultModel resultInsert(){
        boolean flag = false;
        return ResultModel.resultInsert(flag);
    }

    //更新后返回方式, msg:更新成功;更新失败
    public ResultModel resultUpdate(){
        boolean flag = false;
        return ResultModel.resultUpdate(flag);
    }

    //删除后返回方式, msg:删除成功;删除失败
    public ResultModel resultDelete(){
        boolean flag = false;
        return ResultModel.resultDelete(flag);
    }

    //删除后返回方式, msg:操作成功;操作失败
    public ResultModel result(){
        boolean flag = false;
        return ResultModel.result(flag);
    }

    //认证失败返回方式, msg:认证信息异常
    public ResultModel errorTokenMsg(){
        boolean flag = false;
        //如果msg参数为null,那么是默认的msg:认证信息异常
        return ResultModel.errorTokenMsg(null);
    }

Рекомендуется отдать приоритет описанному выше методу замены.Если он не может быть удовлетворен, вы также можете использовать следующий общий失败,成功метод возврата:

ResultModel.error();  //失败返回方式
ResultModel.ok();       //成功返回方式

Вывод журнала АОП

  1. Добавить координаты
<!-- AOP -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- console彩色日志 -->
<dependency>
    <groupId>org.fusesource.jansi</groupId>
    <artifactId>jansi</artifactId>
    <version>1.18</version>
</dependency>
  1. Определите классы АОП для реализации цветного вывода журнала

Ссылаться на:com.zhirui.lmwy.common.aop.LogAop

интегрированные чулки чувак

Интегрируйте swagger в общий проект

  1. добавить комментарии к пом
        <!-- swagger start -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!-- swagger end -->
  1. добавить конфигурацию

    Два класса конфигурации:

    com.zhirui.lmwy.common.swagger.SwaggerConfiguration

    com.zhirui.lmwy.common.swagger.SwaggerProperties

  2. Установить пользовательские параметры отображения

    В базовом проектеapplication.yamlДобавьте следующую конфигурацию для установки:

swagger:
  #  open: true              #是否开启swagger,在生产环境下需要关闭
  protocol: http          #协议,http或https
  base-package: com.zhirui.lmwy.wms   #一定要写对,会在这个路径下扫描controller定义
  title: volcano-base项目
  version: 1.0
  description: volcano-base项目丝袜哥测试
  1. Используйте чванство в контроллере и модели

    Используйте ссылку в классе контроллера:com.zhirui.lmwy.wms.demo.web.controller.TestCurdController

    Используйте ссылку в классе модели:com.zhirui.lmwy.wms.demo.web.entity.User

  2. http-запрос через swagger

    • http://localhost:8080/swagger-ui.html#/

      Метод доступа по умолчанию к чулкам Brother

    • http://localhost:8080/docs

      Метод доступа после перенаправления контроллером

      swagger может сообщить о следующей ошибке в 2.9.2:

      Illegal DefaultValue null for parameter type integer
      

      В соответствии с приведенным выше сообщением об ошибке щелкните AbstractSerializableParameter.java:412, чтобы увидеть

      if(BaseIntegerProperty.TYPE.equals(type)){
          return Long.valueOf(example);
      }
      

      То есть, если тип атрибута сущности — целое число, преобразуйте пример в тип Long, а пример по умолчанию имеет значение "", что приведет к ошибке преобразования.

      Решение

      метод первый: В классе сущностей при добавлении @ApiModelProperty к свойству типа Integer необходимо присвоить значение параметру примера, и это значение должно быть числового типа.

      @ApiModelProperty(value = "试卷ID",example = "1")
      private int pageId;
      

      Способ второй:

      Измените версию на 2.8.0

      <!-- swagger start -->
      <dependency>
          <groupId>io.springfox</groupId>
          <artifactId>springfox-swagger2</artifactId>
          <version>2.8.0</version>
      </dependency>
      <dependency>
          <groupId>io.springfox</groupId>
          <artifactId>springfox-swagger-ui</artifactId>
          <version>2.8.0</version>
      </dependency>
      

Интеграция mybatis-plus (далее MP)

Использование ORM-фреймворкаmybatis-plus, что упрощает работу с CURD

  1. добавить помпон

            <!-- mybatis-plus -->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.2.0</version>
            </dependency>
            <!-- 代码生成器  start -->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-generator</artifactId>
                <version>3.2.0</version>
            </dependency>
            <!-- 代码生成器需要的引擎模板 -->
            <dependency>
                <groupId>org.apache.velocity</groupId>
                <artifactId>velocity-engine-core</artifactId>
                <version>2.0</version>
            </dependency>
            <!-- 代码生成器  end -->
    
  2. настроить в yml

    mybatis-plus:
      mapper-locations: classpath:mapper/**/*.xml
      global-config:
        db-config:
          id-type: AUTO  #主键自增长
    
  3. Добавить конфигурацию класса конфигурации

    Следующий код использует аренду, если просто нужно добавить плагин Pagination, вам нужно только следует следули:

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        return paginationInterceptor;
    }
    
    /** 分页插件: 实现物理分页 */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        ArrayList<ISqlParser> iSqlParsers = new ArrayList<>();
        TenantSqlParser tenantSqlParser = new TenantSqlParser();
        tenantSqlParser.setTenantHandler(new TenantHandler() {
            @Override
            public Expression getTenantId(boolean where) {
                return new StringValue(tenantId);
            }
    
            @Override
            public String getTenantIdColumn() {
                //指定表中的租户列
                return "tenant_id";
            }
            @Override
            public boolean doTableFilter(String tableName) {
                return false;
            }
        });
        iSqlParsers.add(tenantSqlParser);
        paginationInterceptor.setSqlParserList(iSqlParsers);
        return paginationInterceptor;
    }
    

CRUD-операции через MP

Эталонные тестовые классы иОфициальный сайт:com.zhirui.lmwy.wms.demo.web.controller.TestCurdController

Генератор кода

Генератор кода MP принят, и два генератора кода реализованы.

существуетjavasea-volcano-baseПроектsrc/test/javaПод пакетом com.zhirui.lmwy.wms в каталоге следуйте комментариям, чтобы изменить конфигурацию, которую необходимо запустить. Это зависит от личных привычек, рекомендуется использоватьPrimaryCodeGenerator.

  • SencondCodeGenerator

    Базовые классы, такие как классы сущностей, картографов, контроллеров и сервисов, генерируются с помощью таблиц базы данных.

  • PrimaryCodeGenerator

    существуетSencondCodeGeneratorНа основе функции генерируется аннотация swagger в контроллере и сущности. Контроллер и служба генерируют общие грубые методы.

Интегрировать Redis

  1. Добавить координату POM
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

  1. yml для настройки
spring:
    redis:
      host: 127.0.0.1
      port: 6379
      password: zhirui888
      timeout: 2000
      database: 6
      lettuce:
        pool:
          max-active: 8
          max-wait: 1
          max-idle: 8
          min-idle: 0
  1. Настроить в классе конфигурации

    • RedisTemplate, который определяет Redis

      См.: com.zhirui.lmwy.common.redis.RedisTemplateConfig.

    • включить SpringCache

      Смотрите: com.zhirui.lmwy.common.redis.rediscacheconfig.

    • инструменты Redis

      См.: com.zhirui.lmwy.common.redis.RedisUtils

Интеграция JWT

добавить координаты jwt

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
    <scope>compile</scope>
</dependency>

Настроить jwt в yml

custom:
    jwt:
      header: token
      secret: 666666          #密码,用于生成签名
      issuer: volcano         #签发人
      subject: volcano-jwt    #主题
      audience: web           #签发的目标
      expire-minutes: 20      #过期时间
    interceptor:
      jwt:
        exclude:
          path: /swagger-resources/**,/api-docs/**,/v2/api-docs/**,/login,/verificationCode,/doc/**,/error/**,/docs,/test/**
      permission:
        exclude:
          path: /swagger-resources/**,/api-docs/**,/v2/api-docs/**,/adminLogin,/sysLogin,/login.html,/verificationCode,/doc/**,/error/**,/docs
      token-timeout:
        exclude:
          path: /swagger-resources/**,/api-docs/**,/v2/api-docs/**,/docs

Добавить интерфейс входа

После входа в систему информация о токене будет сохранена в Redis.

Подробнее см. в контроллере входа: com.zhirui.lmwy.wms.security.controller.LoginController.

Добавить перехватчик jwt

После того, как запрос будет перехвачен, он будет проверен, метод проверки следующий:

// 验证token是否有效
Jws<Claims> jws = JwtUtil.verify(token);

Если токен не просрочен и не действителен, проверка будет пройдена, в противном случае будет выдано исключение 401.

Подробности смотрите в jwt interceptor: com.zhirui.lmwy.wms.security.interceptor.JwtInterceptor

Тестирование токенов в swagger

  1. Выполните операцию входа в систему, см. токен в возвращаемом значении

Возвращаемое значение:

{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "loginSysUser": {
      "id": "1",
      "userName": "admin"
    },
    "token": "eyJjdHkiOiJjdHkiLCJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ2b2xjYW5vLWp3dCIsImF1ZCI6IndlYiIsImlzcyI6InZvbGNhbm8iLCJleHAiOjE1Njg3MTI0MDcsImlhdCI6MTU2ODcxMDYwNywianRpIjoiNDM4NjMwMDAwOTlmNDFkNDk1Y2FlOWVkNWUzNDZhOTgifQ.wVZOx-J2knqUxdnRjRXZqr2nf1S-Qwmap2-0nGXJDXM"
  },
  "time": "2019-09-17 16:56:51"
}
  1. нажмитеAuthorizeкнопка

  1. Установите значение токена, и все последующие запросы будут иметь заголовок запроса с именем «Авторизация».

    в перехватчике jwtJwtInterceptorЗаголовок запроса будет получен для проверки.

Запуск и развертывание проекта

Использовать отдельно как проект

javasea-volcanoПо умолчанию это независимый проект Springboot, который можно запустить напрямую.javasea-volcano-baseпроект, вbaseНа основе проекта можно напрямую писать бизнес-код.

Интеграция в существующий springcloud

  1. Включить настройку bootstrap.yml (отпустить комментарии)

    #spring:
    #  cloud:
    #    config:
    #      uri: ${WMS_CONFIG_SERVER_URL}
    #      name: zhirui-lmwy2-wms${WMS_DEVELOPER_NAME:}
    #      profile: ${config.profile:dev}
    #
    
  2. Откройте координаты соответствующего клиента eureka в pom базового проекта и запустите классWmsApplicationчерез аннотацию@EnableDiscoveryClientВключите клиент eureka.

    <!-- springboot 1.X -->
    <!--<dependency>-->
       <!--<groupId>org.springframework.cloud</groupId>-->
       <!--<artifactId>spring-cloud-starter-eureka</artifactId>-->
    <!--</dependency>-->
    <!-- springboot 2.X -->
    <!--<dependency>-->
       <!--<groupId>org.springframework.cloud</groupId>-->
       <!--<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
    <!--</dependency>-->
    
  3. Настройте параметры vm в IDE и используйте существующиеeureka注册中心и配置中心

    Настройка параметров ВМ в среде IDE может использоваться только в качестве теста, если она должна вступить в силу после развертывания, необходимо настроить переменные среды сервера или добавить конфигурацию после запуска java -jar. Я добавлю статью о развертывании службы позже.

    -Dmultipart-location=D:/wms/temp
    -DDiskLocation=D:/wms/
    -DWMS_CONFIG_SERVER_URL=http://192.168.1.230:8861
    -DWMS_EUREKA_SERVER_URL=http://192.168.1.230:8090/eureka/
    -DWMS_DEVELOPER_NAME=-longxiaonan
    -Dconfig.profile=dev
    

Мейвен упаковка

mvn clean package -Dmaven.test.skip=true