idea创建spring通用项目

创建spring基础项目

高清地址点此播放

springBoot: 3.2
java: v21
mybatis: v3.2.4.1
swagger: v3

初始化完成后,我们看看pom文件会发现 已经把我们最基本的spring所需要的依赖项加上去了

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

但是这是远远不够的,请接着往下看,我会带你慢慢把项目补充完整!

添加代码生成

一般情况下,对于单表的增删改查,我们并不会手动一个个实现,这样太麻烦了。
这里我是用的是mybatis-plus-generator,我们这个依赖包 加上!

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>LATEST</version>
</dependency>

同时再创建一个生成工具类utils/CodeGenerator.java

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

public class CodeGenerator {
    public static String projectPath = System.getProperty("user.dir");
    public static String dateBaseUrl = "jdbc:mysql://dingshaohua.mysql.rds.aliyuncs.com:3306/emr?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false";

    public static void main(String[] args) {
        FastAutoGenerator generator = FastAutoGenerator.create(dateBaseUrl, "root", "******");
        generator.globalConfig(builder -> {
                    builder.author("丁少华") // 设置作者
                            // .enableSwagger() // 开启 swagger 模式(暂时放弃,swagger的主流库已经放弃维护,且不支持springBoot v3,所以推荐兼容swagger的官方库Springdoc)
                            .enableSpringdoc() // 开启 SpringDoc 模式
                            .outputDir(projectPath + "/src/main/java/"); // 指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent("com.example.demo") // 设置父包名 我这里没有
                            .moduleName("") // 设置父包模块名 我这里没有
                            .pathInfo(Collections.singletonMap(OutputFile.xml, projectPath + "/src/main/resources/mapper/")); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder.addInclude("medical_record") // 设置需要生成的表名
                            .addTablePrefix()// 设置过滤表前缀. 我的表没有前缀
                            .entityBuilder().enableFileOverride() // 覆盖已生成文件
                            .serviceBuilder().enableFileOverride()
                            .mapperBuilder().enableFileOverride()
                            .controllerBuilder().enableFileOverride();

                })
                .templateEngine(new FreemarkerTemplateEngine()) // 模板是必须的,默认的是Velocity引擎模板,这里我们改为Freemarker引擎模板
                .execute();
    }
}

根据代码生成类CodeGenerator,我们得知需要两个方面的依赖,swagger相关、Freemarker相关

<dependency> <!--framework模板引擎:使用代码生成器时必须要的模板引擎依赖,否则生成期间也会报错。-->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
    <version>LATEST</version>
</dependency>

<!--swagger3:生成若开启了springDoc,那生后的代码需要此库 【可选,看逆向工具是否配置】 start-->
<!-- io.springfox的springfox-boot-starter已经放弃维护了且也不兼容springBoot v3,开启后无法启动项目。而springdoc则是spring官方出的-->
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
    <version>LATEST</version>
</dependency>
<!--该依赖里面使用了 swagger-ui,以HTML形式展示文档。 如果你想网页的方式查看接口文档,则需要此依赖-->
<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
    <version>LATEST</version>
</dependency>
<!--swagger3:生成若开启了springDoc,那生后的代码需要此库 【可选,看逆向工具是否配置】end-->

生成项目

此时我们运行CodeGenerator的main方法执行代码生成,会发现报错 CodeGenerator Exception in thread "main" java.lang.NoClassDefFoundError: com/baomidou/mybatisplus/core/toolkit/StringUtils

根据提示可知,mybatis-plus-generator包依赖mybatis-plus-boot-starter,那么我们加上它依赖包便可

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>LATEST</version>
</dependency>

接着我们再次执行CodeGenerator的main方法 来进行代码生成,会发现依然报错No suitable driver found for jdbc:mysql://...
我们可得知,是缺少数据库驱动无法读取数据库生成代码,那么我们安装数据库驱动

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

启动项目

此时我们再启动项目,还报错Unsatisfied dependency expressed through field 'baseMapper'
这是没有配置mybatis相关信息所导致,我们做一下两步即可解决
在项目配置文件application.yml中加入如下代码

spring:
  datasource:  # 这个配置是给mybatis用的,不是给mybatis-generator用的
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://xxx.com:3306/emr?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false
    username: root
    password: 'xxx'

在启动类上指定扫描路径的注解@MapperScan("com.example.demo.mapper")

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan("com.example.demo.mapper")
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

最后我们再次启动项目,发现依然报错Invalid value type for attribute 'factoryBeanObjectType': java.lang.String

最终定位是 springBoot不兼容MyBatis v2.1.1所致,我跟踪了半天 发现是因为MyBatis Plus(mybatis-plus-boot-starter)里依赖了MyBatis v2.1.1,于是再pom文件指定MyBatis高版本即可。

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>LATEST</version>
</dependency>

再次气启动,就成功啦


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.2.0)

[main] com.example.demo.DemoApplication         : Starting DemoApplication using Java 21.0.1 with PID 10068 (demo\target\classes started by Administrator in IdeaProjects\demo)
[main] com.example.demo.DemoApplication         : No active profile set, falling back to 1 default profile: "default"
[main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
[main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
[main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.16]
[main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
[main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 555 ms
 _ _   |_  _ _|_. ___ _ |    _ 
| | |\/|_)(_| | |_\  |_)||_|_\ 
     /               |         
                        3.5.4.1 
[main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path ''
[main] com.example.demo.DemoApplication         : Started DemoApplication in 1.266 seconds 

使用swagger(可选)

springdoc兼容且包含swagger-ui
当你springdoc.swagger-ui安装依赖后, 它默认为即启动,
所以我们直接访问就行:http://localhost:8080/swagger-ui/index.html

很多同学不喜欢 swagger-ui 的界面风格,会集成 knife4j 的 ui,但是我就不,嘿嘿

freemarker的配置(可选)

在application.yml文件增加如下配置:

spring:
  freemarker:
    enabled: true
    charset: UTF-8 #编码
    suffix: .html #后缀名
    content-type: text/html
    prefer-file-system-access: true
    template-loader-path: classpath:/templates/ #模板位置

resources\templates\index.html新增一个页面,内容随意
新增一个控制器类,写入路由

import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

@RequestMapping
@RestController
public class OtherController {
    @ApiOperation(value = "后端服务起始页", notes = "用于用查看后端服务是否启动", produces = "text/html")
    @GetMapping("/")
    public ModelAndView Home() {
        return new ModelAndView("index");
    }
}

最后重启访问即可

统一返回值(可选)

后端返回格式是统一的,如有status、data、msg等等,所以我们需要做一个规范。

pom里增加一个依赖

<!--Json序列化工具,编写JsonResult类用到了-->
<dependency>
  <groupId>org.junit.platform</groupId>
  <artifactId>junit-platform-commons</artifactId>
</dependency>

新建一个格式化返回值的类\utils\JsonResult.java内容如下:

import org.junit.platform.commons.util.ToStringBuilder;
import java.io.Serializable;
import java.util.Objects;

public class JsonResult<T> implements Serializable {

    private static final long serialVersionUID = 5598308977637490090L;

    private int code;

    private String msg;

    private T data;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public void setData(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }

    public static JsonResult success() {
        return success(null);
    }

    public static <T> JsonResult success(T data) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setCode(0);
        jsonResult.setMsg("SUCCESS");
        if (data != null) {
            jsonResult.setData(data);
        }
        return jsonResult;
    }

    public static JsonResult failed() {
        return failed("FAILED");
    }

    public static JsonResult failed(String msg) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setCode(1);
        jsonResult.setMsg(msg);
        return jsonResult;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof JsonResult)) {
            return false;
        }
        JsonResult result = (JsonResult) o;
        return code == result.code &&
                Objects.equals(msg, result.msg) &&
                Objects.equals(data, result.data);
    }

    @Override
    public int hashCode() {
        return Objects.hash(code, msg, data);
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this)
                .append("code", code)
                .append("msg", msg)
                .append("data", data)
                .toString();
    }

}

控制器里使用

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.MedicalRecord;
import com.example.demo.service.IMedicalRecordService;
import com.example.demo.utils.JsonResult;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping
@RestController
public class OtherController {
    @ApiOperation(value = "测试接口", notes = "用于测试后台是否可被访问", produces = "application/json")
    @GetMapping("/test")
    public JsonResult Login() {
        return JsonResult.success();
    }
}

添加分页能力(可选)

参考:https://baomidou.com/pages/2976a3/#spring
首先给mybatis添加分页插件
创建一个mybatis配置文件utils/MybatisPlusConfig.java ,并进行配置

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {
    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
        return interceptor;
    }
}

开始使用

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.MedicalRecord;
import com.example.demo.service.IMedicalRecordService;
import com.example.demo.utils.JsonResult;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

/**
 * <p>
 *  病例管理
 * </p>
 *
 * @author 丁少华
 * @since 2023-11-28
 */
@RestController
@RequestMapping("/medicalRecord")
public class MedicalRecordController {
    @Autowired
    private IMedicalRecordService medicalRecordService;

    @ApiOperation("病例列表")
    @GetMapping
    private JsonResult<IPage<MedicalRecord>> getList(Integer current, Integer size) {
        if(ObjectUtils.isEmpty(current) || ObjectUtils.isEmpty(size)){ //如果没有分页
            List<MedicalRecord> moods = medicalRecordService.list();
            return JsonResult.success(moods);
        }else{
            // 要想使用page分页能力,必须提前给mybatis添加分页插件
            IPage<MedicalRecord> moods = medicalRecordService.page(new Page(current, size),new QueryWrapper<MedicalRecord>());
            return JsonResult.success(moods);
        }
    }
}

效果

全局异常处理(可选)

全局异常处理
这个很实用,比如登陆超时啊啥的
新增处理异常类exception/GlobalExceptionHandler.java

import cn.dev33.satoken.exception.NotLoginException;
import com.example.demo.utils.JsonResult;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletRequest;
import java.sql.SQLIntegrityConstraintViolationException;

//ExceptionHandler的处理顺序是由异常匹配度来决定的,且我们也无法通过其他途径指定顺序(其实也没有必要)
/**
 * 全局异常处理器
 */
@ControllerAdvice // @ControllerAdvice将当前类标识为异常处理的组件
@RestController
public class GlobalExceptionHandler {
    @ExceptionHandler(NotLoginException.class)
    @ResponseStatus(HttpStatus.OK)
    protected JsonResult handleException(HttpServletRequest request, NotLoginException ex) {
        JsonResult result = new JsonResult();
        result.setCode(401);
        result.setMsg("用户未登录或已过期,请重新登录");
        return result;
    }

    @ExceptionHandler(DuplicateKeyException.class)
    @ResponseStatus(HttpStatus.OK)
    public JsonResult handleException(HttpServletRequest req, DuplicateKeyException ex) {
        JsonResult result = new JsonResult();
        result.setCode(1);
        result.setMsg("数据库已经存在");
        return result;
    }

    @ExceptionHandler(Exception.class)  // @ExceptionHandler用于设置所标识方法处理的异常 参数代表异常类型
    @ResponseStatus(HttpStatus.OK)
    public JsonResult handleException(HttpServletRequest req, Exception ex) {
        ex.printStackTrace();
        JsonResult result = new JsonResult();
        result.setCode(1);
        result.setMsg("系统错误");
        return result;
    }
}

------分割线-------

以下2022年创建的一篇,推荐不要看,为了整合 放一起了

v1.0.0

最普通SpringWeb版本,只有一空的项目

如图,如果我们勾选Spring Web了,意味着这是一个springWeb项目,毕竟Spring又不是只可以做web端。
我们来对比下,勾选与否的区别。

勾选吗? resources目录 pom.xml
- spring-boot-starter
多出空文件夹templates、static spring-boot-starter-web

也就是说,springWeb项目会多出一些存放页面相关的文件结构,并且依赖也升级到spring-boot-starter-web。
spring-boot-starter-web包含spring-boot-starter,并再此基础上多出了一些web相关的其它模块。

1.0.1

增加了如下功能,
逆向代码生成

pom变化

相比v1.0.0最基本得空框架而言,这需在pom增加如下依赖:

<!--这是逆向工程所所需依赖,一共5个包 start-->
<dependency><!-- 链接数据库驱动: 在idea初始化项目中,选了sql>mysql drive就会有此项,mybatis和逆向都需要 -->
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency> <!-- mybatis-plus(springBoot版)-->
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.0</version>
</dependency>
<dependency><!--mybatis-plus代码生成器,3.5之后独立出来了(这个生成代码后就可以删除了,毕竟只用一次)-->
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.1</version>
</dependency>
<dependency> <!--模板引擎:使用代码生成器时必须要的模板引擎依赖。-->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency><!--SpringFox 3.0.0(swagger2支持):这个可选。逆向工具是否开启,自己是否需要2个条件决定  https://blog.csdn.net/fygkchina/article/details/109316824 start-->
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

解释一下:
mysql-connector-java 是mybatis和mybatis generator都要用到的连接数据库驱动包。
mybatis-plus 就是mybatis的升级版本,是一款优秀的基于java的持久层框架。业务涉及到操作数据库or逆向生成都需要此包。
mybatis-plus-generator 逆向代码生成工具包,生成完代码后,就可以删掉它了。
spring-boot-starter-freemarker 后端得模板语言包,这个如果你用了逆向生成,则必须要使用这个包。 至于逆向为啥要用模板,我也不知道,没有百度到。
springfox-boot-starter swagger2包,用来生成接口api工具的 逆向生成配置如果开启此功能,则需要下载此依赖,可选。

swagger2处理

swagger2因为升级到了3.0.0,所以和现有的spring2.6.x不兼容,Failed to start bean 'documentationPluginsBootstrapper'
百度到一些 资料 , 需要做额外适配, application.yml文件增加如下代码:

spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

然后再启动类上增加@EnableOpenApi注解

@EnableOpenApi
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SbDemoApplication.class, args);
    }
}

mybatis generator处理

逆向工程时候,需要增加一个逆向配置类 utils\CodeGenerator.java

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.Collections;

public class CodeGenerator {
    public static String projectPath = System.getProperty("user.dir");
    public static String dateBaseUrl = "jdbc:mysql://xxx:3306/demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false";
    public static void main(String[] args) {
        FastAutoGenerator.create(dateBaseUrl, "root", "*****")
                .globalConfig(builder -> {
                    builder.author("丁少华") // 设置作者
                            .enableSwagger() // 开启 swagger 模式(非必须,如果开启,需要在依赖添加swagger以及启动类加注解)
                            .fileOverride() // 覆盖已生成文件
                            .outputDir(projectPath+"/src/main/java/"); // 指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent("com.dshvv.demo") // 设置父包名 我这里没有
                            .moduleName("") // 设置父包模块名 我这里没有
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, projectPath+"/src/main/resources/mapper/")); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder.addInclude("blog") // 设置需要生成的表名
                            .addTablePrefix(); // 设置过滤表前缀. 我的表没有前缀
                })
                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();
    }
}

然后运行这个类的main方法,代码就生成了

mybatis配置

如果此时直接启动项目,则会报错,提示缺少数据库配置。原来mybatis generator的配置文件和mybatis不能公用
此时在application.yml文件配置一下数据库就行:

spring:
  datasource:  # 这个配置是给mybatis用的,不是给mybatis-generator用的
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://xxx:3306/demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false
    username: root
    password: 'xxx'

此时在启动项目即可。
不过,可能还会发现如下报错Unsatisfied dependency expressed through field 'baseMapper'
意思是扫描不到mapper文件,我们在启动类上指定扫描路径的注解@MapperScan("com.dshvv.sbdemo.mapper")即可

@MapperScan("com.dshvv.sbdemo.mapper")
@SpringBootApplication
public class SbDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SbDemoApplication.class, args);
    }
}

freemarker的配置

1、在application.yml文件增加如下配置:

spring:
  freemarker:
    enabled: true
    charset: UTF-8 #编码
    suffix: .html #后缀名
    content-type: text/html
    prefer-file-system-access: true
    template-loader-path: classpath:/templates/ #模板位置

2、resources\templates\index.html新增一个页面,内容随意
3、新增一个控制器类,写入路由

package com.dshvv.demo.controller;

import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

@RequestMapping
@RestController
public class OtherController {
  @ApiOperation(value = "后端服务起始页", notes = "用于用查看后端服务是否启动", produces = "text/html")
  @GetMapping("/")
  public ModelAndView Home() {
    return new ModelAndView("index");
  }
}

重启,即可访问

controller优化

后端返回格式是统一的,如有status、data、msg等等,所以我们需要做一个规范。
1、pom里增加一个依赖

<!--Json序列化工具,编写JsonResult类用到了-->
<dependency>
  <groupId>org.junit.platform</groupId>
  <artifactId>junit-platform-commons</artifactId>
</dependency>

2、新建一个格式化返回值的类
\utils\JsonResult.java内容如下:

package com.dshvv.demo.utils;

import org.junit.platform.commons.util.ToStringBuilder;
import java.io.Serializable;
import java.util.Objects;

public class JsonResult implements Serializable {

    private static final long serialVersionUID = 5598308977637490090L;

    private int status;

    private String message;

    private Object data;

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public Object getData() {
        return data;
    }

    public static JsonResult success() {
        return success(null);
    }

    public static JsonResult success(Object data) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setStatus(200);
        jsonResult.setMessage("SUCCESS");
        if (data != null) {
            jsonResult.setData(data);
        }
        return jsonResult;
    }

    public static JsonResult failed() {
        return failed("FAILED");
    }

    public static JsonResult failed(String message) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setStatus(500);
        jsonResult.setMessage(message);
        return jsonResult;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof JsonResult)) {
            return false;
        }
        JsonResult result = (JsonResult) o;
        return status == result.status &&
                Objects.equals(message, result.message) &&
                Objects.equals(data, result.data);
    }

    @Override
    public int hashCode() {
        return Objects.hash(status, message, data);
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this)
                .append("status", status)
                .append("message", message)
                .append("data", data)
                .toString();
    }

}

3、如何使用?
建一个路由,尝试使用

package com.dshvv.demo.controller;

import com.dshvv.demo.utils.JsonResult;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

@RequestMapping
@RestController
public class OtherController {
  @ApiOperation(value = "测试接口", notes = "用于测试后台是否可被访问", produces = "application/json")
  @GetMapping("/test")
  public JsonResult Login() {
    return JsonResult.success();
  }
}

重启访问即可

v1.0.2

增加登陆授权

添加依赖

采取的是Sa-Token 权限认证.

<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot-starter</artifactId>
    <version>1.28.0</version>
</dependency>

如果用默认推荐的给每个控制器方法添加鉴权功能,显然不合适,所以我们通过全局拦截器来处理整个项目的
增加一个拦截器文件interceptor/SaTokenConfigure.java

package com.dshvv.blogserver.interceptor;

import cn.dev33.satoken.interceptor.SaRouteInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * <p>
 *  SaToken全局拦截器,校验登录
 *  参考 https://www.cnblogs.com/yunchu/p/14304900.html、
 *  参考 https://www.cnblogs.com/yunchu/p/14362461.html (重点)
 * </p>
 *
 * @author 丁少华
 * @since 2022-01-07
 */

@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
    // 注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册Sa-Token的路由拦截器
        registry.addInterceptor(new SaRouteInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/login","/reg")
                .excludePathPatterns("/swagger**/**", "/v3/**", "/doc.html","/webjars/**"); //排除swagger设置
    }
}

对SaToken插件进行配置

其实这个是非必需,因为不配置都有默认值,但是为了为了学习,和实验,还是配置一下吧,
application.yml增加如下配置

sa-token:
  token-name: satoken # token名称 (同时也是cookie名称)
  timeout: 5 # token有效期,单位s 默认30天, -1代表永不过期

验证配置结果

如何看SaToken是否生效呢?
当然是写一个控制器,启动项目,用postMan测试接口啦。

package com.dshvv.blogserver.controller;

import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import com.dshvv.blogserver.service.IUserService;
import com.dshvv.blogserver.utils.JsonResult;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.Map;

@RequestMapping
@RestController
public class OtherController {
    @ApiOperation(value = "测试接口", notes = "用于测试后台是否可被访问", produces = "application/json")
    @GetMapping("/test")
    public JsonResult doTest() {
        return JsonResult.success();
    }

    // 登录
    @ApiOperation(value = "登录接口", notes = "用于用户登录", produces = "application/json")
    @PostMapping("/login")
    public SaResult doLogin(@RequestBody Map<String, Object> user) {
        String name = (String) user.get("name");
        String pwd = (String) user.get("pwd");
        // 此处仅作模拟示例,真实项目需要从数据库中查询数据进行比对
        if("yan".equals(name) && "yh@0020".equals(pwd)) {
            StpUtil.login(10001);
            return SaResult.ok("登录成功");
        }
        return SaResult.error("登录失败");
    }
}

除此之外在启动项目的时候,启动类可以打印输出当前SaToken正在使用的配置项,用来确认application.yml配置是否生效

@SpringBootApplication
public class DemoServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoServerApplication.class, args);
        System.out.println("启动成功:Sa-Token配置如下:" + SaManager.getConfig());
    }
}

v1.0.3

增加全局跨域处理
同样,偷懒也不想用@CrossOrigin一个个的去注解类来解决跨域,所以同样的用拦截器
增加处理跨域的全局拦截器类interceptor/CorsConfigurer.java

package com.dshvv.blogserver.interceptor;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * <p>
 *  跨域处理 
 *  参考: http://www.telami.cn/2019/springboot-resolve-cors/
 * </p>
 *
 * @author 丁少华
 * @since 2022-01-07
 */
@Configuration
public class CorsConfigurer implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
                .allowCredentials(true)
                .maxAge(3600)
                .allowedHeaders("*");
    }
}

v1.0.4

全局异常处理
这个很实用,比如登陆超时啊啥的
新增处理异常类exception/GlobalExceptionHandler.java

package com.dshvv.blogserver.exception;

import cn.dev33.satoken.exception.NotLoginException;
import com.dshvv.blogserver.utils.JsonResult;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.sql.SQLIntegrityConstraintViolationException;

//ExceptionHandler的处理顺序是由异常匹配度来决定的,且我们也无法通过其他途径指定顺序(其实也没有必要)

/**
 * 全局异常处理器
 */
@ControllerAdvice // @ControllerAdvice将当前类标识为异常处理的组件
@RestController
public class GlobalExceptionHandler {

    @ExceptionHandler(NotLoginException.class)
    @ResponseStatus(HttpStatus.OK)
    protected JsonResult handleException(HttpServletRequest request, NotLoginException ex) {
        JsonResult result = new JsonResult();
        result.setCode(401);
        result.setMsg("用户未登录或已过期,请重新登录");
        return result;
    }

    @ExceptionHandler(DuplicateKeyException.class)
    @ResponseStatus(HttpStatus.OK)
    public JsonResult handleException(HttpServletRequest req, DuplicateKeyException ex) {
        JsonResult result = new JsonResult();
        result.setCode(1);
        result.setMsg("邮箱已经被注册");
        return result;
    }

    @ExceptionHandler(Exception.class)  // @ExceptionHandler用于设置所标识方法处理的异常 参数代表异常类型
    @ResponseStatus(HttpStatus.OK)
    public JsonResult handleException(HttpServletRequest req, Exception ex) {
        ex.printStackTrace();
        JsonResult result = new JsonResult();
        result.setCode(1);
        result.setMsg("系统错误");
        return result;
    }
}
posted @ 2023-11-28 13:20  丁少华  阅读(240)  评论(2编辑  收藏  举报