(二)Springboot + vue + 达梦数据库构建RBAC权限模型前后端分离脚手架保姆级教程(后端项目)
XX后台管理系统
开源地址:git clone https://gitee.com/mrlumin/x-dm-server.git
Springboot + vue + dm8 的前后端分离项目,后端项目
https://spring.io
https://start.aliyun.com
1. 创建项目
初始化项目,导入坐标
web、lombok、devtools
<!-- web start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- web end -->
<!-- devtools start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- devtools end -->
<!-- lombok start -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- lombok end -->
2.整合Swagger3
2.1 导入swagger3坐标
<swagger3.version>3.0.0</swagger3.version>
<!-- swagger3 start -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>${swagger3.version}</version>
</dependency>
<!-- swagger3 end -->
2.2 编写swagger3配置类
package org.cn.common.config;
import io.swagger.annotations.ApiOperation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
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
@EnableWebMvc
public class Swagger3Config {
/**
* 创建API
* http:localhost:9999/swagger-ui/index.html 原生地址
*/
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.OAS_30).pathMapping("/")
// 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
/*.enable(enable)*/
.apiInfo(apiInfo())
// 设置哪些接口暴露给Swagger展示
.select()
// 扫描所有有注解的api,用这种方式更灵活
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
// 扫描指定包中的swagger注解
//.apis(RequestHandlerSelectors.basePackage("com.cn"))
// 扫描所有 .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(new ApiKey("Authorization", "Authorization", "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;
}
/**
* 添加摘要信息
* @return 返回ApiInfo对象
*/
private ApiInfo apiInfo() {
// 用ApiInfoBuilder进行定制
return new ApiInfoBuilder()
// 设置标题
.title("接口文档")
// 服务条款
.termsOfServiceUrl("NO terms of service")
// 描述
.description("权限模型管理系统-接口文档")
// 作者信息
.contact(new Contact("LM", "https://www.cnblogs.com/longronglang/", "lumin@gmail.com"))
// 版本
.version("版本号:V1.0")
//协议
.license("The Apache License")
// 协议url
.licenseUrl("https://www.apache.org/licenses/LICENSE-2.0.html")
.build();
}
}
2.3 swagger3注解测试
新增测试类、测试方法等,加上Swagger3注解进行测试
http:localhost:9999/swagger-ui/index.html
@Api(tags = "用户管理")
@ApiOperation("用户登录")
http://localhost:9999/swagger-ui/index.html
3. 代码自动生成
3.1 引入MP&DB坐标
mybatis-plus-boot-starter、mybatis-plus-generator、freemarker、dameng
注意:mybatis-plus 坐标引入的是mybatis-plus启动坐标和代码生成坐标
<dm.version>8.1.2.192</dm.version>
<mybatis-plus-boot.version>3.5.3.1</mybatis-plus-boot.version>
<mybatis-plus-generator.version>3.5.3.1</mybatis-plus-generator.version>
<!-- mybatis-plus-boot start -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus-boot.version}</version>
</dependency>
<!-- mybatis-plus-boot end -->
<!-- mybatis-plus-generator start -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatis-plus-generator.version}</version>
</dependency>
<!-- mybatis-plus-generator end -->
<!-- freemarker start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- freemarker end -->
<!-- dameng start -->
<dependency>
<groupId>com.dameng</groupId>
<artifactId>DmJdbcDriver18</artifactId>
<version>${dm.version}</version>
</dependency>
<!-- dameng end -->
3.2 代码生成工具类编写
3.2.1 代码生成工具类
package generator;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Collections;
public class CodeGenerator {
static String url ="jdbc:dm://LOCALHOST:5236";
static String username ="SYSDBA";
static String password ="SYSDBA001";
static String moduleName ="system";
static String javaLocation ="F:\\install\\workspace\\sty\\x-dm-server\\src\\main\\java";
static String mapperLocation ="F:\\install\\workspace\\sty\\x-dm-server\\src\\main\\resources\\mapper\\";
static String tables = "x_user,x_role,x_menu,x_user_role,x_role_menu";
public static void main(String[] args) {
FastAutoGenerator.create(url,username,password)
.globalConfig(builder -> builder
.author("LuMin")
.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.outputDir(javaLocation)
.commentDate("yyyy-MM-dd")
)
.packageConfig(builder -> builder
.parent("org.cn") // 设置父包名
.moduleName(moduleName) // 设置父包模块名
.entity("entity")
.mapper("mapper")
.service("service")
.serviceImpl("service.impl")
.pathInfo(Collections.singletonMap(OutputFile.xml, mapperLocation))
)
.strategyConfig(builder -> builder
.addInclude(tables) // 设置需要生成的表名
.addTablePrefix("x_") // 设置过滤表前缀
.entityBuilder()
.enableLombok()
)
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
public static class Test {
static Connection con = null;
static String cname = "dm.jdbc.driver.DmDriver";
static String url = "jdbc:dm://192.168.106.137:30236";
static String userid = "SYSDBA";
static String pwd = "SYSDBA001";
public static void main(String[] args) {
try {
Class.forName(cname);
con = DriverManager.getConnection(url, userid, pwd);
con.setAutoCommit(true);
System.out.println("[SUCCESS]conn database");
} catch (Exception e){
System.out.println("[FAIL]conn database:" + e.getMessage());
}
}
public void disConn(Connection con) throws SQLException {
if (con != null) {
con.close();
}
}
}
}
3.2.2 启动异常解决
注意生成代码之后,直接启动项目会报错,需要对项目信息进行修改
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'menuServiceImpl': Unsatisfied dependency expressed through field 'baseMapper'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.cn.system.mapper.MenuMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
# ①修改启动类扫描的包
@SpringBootApplication(scanBasePackages = {"org.cn"})
@MapperScan(value = {"org.cn.*.mapper"})
# ②在Mapper接口上增加@Mapper类注解,启动还是会报错
initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'menuServiceImpl': Unsatisfied dependency expressed through field 'baseMapper'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'menuMapper' defined in file
# ③删除创建项目默认生成的demos包,重新启动
3.3 application.yml配置
# server
server:
port: 9999
# datasource
spring:
datasource:
url: jdbc:dm://LOCALHOST:5236/XGIS
username: SYSDBA
password: SYSDBA001
driver-class-name: dm.jdbc.driver.DmDriver
jpa:
database-platform: org.hibernate.dialect.DMDialect
hibernate:
ddl-auto: update # 或者 create, create-drop, validate, none
show-sql: true # 显示执行的 SQL 语句,便于调试
properties:
hibernate:
format_sql: true # 格式化 SQL 语句输出
redis:
port: 6379
password: Admin@123
host: localhost
# mybatis-plus
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
global-config:
db-config:
logic-delete-field: deleted
logic-not-delete-value: 0
logic-delete-value: 1
mapper-locations: classpath*:mapper/*.xml
type-aliases-package: org.cn
# logging
logging:
charset:
console: utf-8
level:
org.cn: debug
3.4 测试生成代码生成可用性
利用SpringBootJunit测试工具进行测试,在XDmServerApplicationTests类中新建testUserMapper()方法
package org.cn;
import org.cn.system.entity.User;
import org.cn.system.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class XDmServerApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
}
@Test
void testUserMapper () {
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
foreach循环时没有打印出预期的内容(例如用户对象的某些属性),而是打印出了类似org.cn.system.entity.User@1ad1c363这样的内容,这通常意味着你没有正确覆写User类的toString方法。
org.cn.system.entity.User@76d0ecd7
org.cn.system.entity.User@57c69937
org.cn.system.entity.User@1ad1c363
org.cn.system.entity.User@446b64b3
org.cn.system.entity.User@35ac9ebd
org.cn.system.entity.User@56c0a61e
一是在User实体类中增加 toString()方法
二是在实体类上添加@Data/@NoArgsConstructor/@AllArgsConstructor注解
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
", status='" + status + '\'' +
", phone=" + phone +
", avatar='" + avatar + '\'' +
", deleted=" + deleted +
'}';
}
4. 统一结果返回封装
4.1 封装公共响应类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result
/**
* 返回编码
/
private Integer code;
/*
* 返回信息
/
private String message;
/*
* 返回数据
*/
private T data;
/**
* 返回成功
* @return
* @param
*/
public static
return new Result<>(20000, "success",null);
}
public static
return new Result<>(20000, "success",data);
}
public static
return new Result<>(20000, message,data);
}
public static
return new Result<>(20000, message,null);
}
/**
* 返回失败
* @return
* @param
*/
public static
return new Result<>(20001, "fail",null);
}
public static
return new Result<>(20001, "fail",null);
}
public static
return new Result<>(20001, message,null);
}
public static
return new Result<>(20001, message,null);
}
}
4.2 测试公共响应类
修改控制器,测试公共响应类是否返回自定义数据
4.2.1 修改注解
修改UserController控制器的@Controller为@RestController
4.2.2 新增方法测试
在控制类中注入IUserService接口服务类,新增getUserList()测试方法进行测试
@Resource
private IUserService userService;
@GetMapping("/getUserList")
public Result<List<User>> getUserList() {
List<User> userList = userService.list();
return Result.success(userList, "查询成功");
}
5.实体类Lombok改造
5.1 删除注解
@Getter/@Setter是mybatis-plus-generator生成实体时自动添加的注解
@Getter
@Setter
5.2 新增注解
@Data/@NoArgsConstructor/@AllArgsConstructor是lombok中的注解
@Data
@NoArgsConstructor
@AllArgsConstructor
6.JWT登录实现
6.1 JWT 整合
6.1.1 导入Jwt坐标
spring-security-core、jjwt
<jjwt.version>0.9.1</jjwt.version>
<!-- spring-security-core start -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
<!-- spring-security-core end -->
<!-- jjwt start -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
<!-- jjwt end -->
6.1.2 编写Jwt工具类
①在application.yml配置JWT令牌和有效期
# JWT 配置
jwt:
secret-key: 123456
token-validity-in-seconds: 86400000
②JwtUtil工具类
6.1.3 Jwt验证拦截器
6.1.3.1 定义Jwt拦截器
@Component
@Slf4j
public class JwtValidateInterceptor implements HandlerInterceptor {
@Resource
private JwtUtil jwtUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// String token = request.getHeader("Authorization");
/request.getHeader()方法与集成Swagger中ApiKey并无多大关系
private List
List
securitySchemes.add(new ApiKey("Authorization", "Authorization", "header"));
return securitySchemes;
}
String token = request.getHeader("X-Token");
log.debug(request.getRequestURI()+"需要验证"+token);
if (token != null) {
try {
jwtUtil.parseToken(token);
log.debug(request.getRequestURI()+"验证通过");
return true;
} catch (Exception e) {
throw new Exception(e);
}
}
log.debug(request.getRequestURI()+"验证失败,禁止访问");
response.setContentType("application/json;charset=utf-8");
Result
本文来自博客园,作者:screws,转载请注明原文链接:https://www.cnblogs.com/mrlumin/p/18602826
浙公网安备 33010602011771号