1.使用spring initializr创建项目

注意:然后低下提供的依赖可用可不用,先不用,后边Maven统一配置依赖,注意:不要用3.0, 3.0需要用java17, 所以使用2x版本

2.导入依赖
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mysql -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.2</version>
</dependency>
<!-- freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
3.配置yml
如果没有yml就自己在资源包建造一个

server:
port: 9999
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql:///xdb
logging:
level:
com.lantu: debug
注意: url: jdbc:mysql:///xdb 这里的第三个斜杠 代替了localhost (是一种简写)
4.Mybatis-plus代码生成
下面是一个例子,不过可以通用,
当然mybatis-plus官网,也有代码生成器例子,
不过既然写好了,以后用这一个模版也行,,后面有什么新的需求在加
需要三个依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.2</version>
</dependency>
<!-- freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
public static void main(String[] args) {
String url = "jdbc:mysql:///xdb";
String username = "root";
String password = "123456";
String author = "mu";
String outputDir = "D:\\Code\\x-admin\\src\\main\\java";
String basePackage = "com.mu";
String moduleName = "sys";
String mapperLocation = "D:\\Code\\x-admin\\src\\main\\resources\\mapper\\" + moduleName;
String tableName = "x_user,x_menu,x_role,x_role_menu,x_user_role";
String tablePrefix = "x_";
FastAutoGenerator.create(url, username, password)
.globalConfig(builder -> {
builder.author(author) // 设置作者
// .enableSwagger() // 开启 swagger 模式
//.fileOverride() // 覆盖已生成文件
.outputDir(outputDir); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent(basePackage) // 设置父包名
.moduleName(moduleName) // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.xml, mapperLocation)); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude(tableName) // 设置需要生成的表名
.addTablePrefix(tablePrefix); // 设置过滤表前缀
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
使用mybatisplus代码生成器问题
Failed to execute goal org.codehaus.mojo:exec-maven-plugin:3.1.0:exec (default-cli) on project x-admin: Command execution failed.

原因是因为,在官方的测试文档目录下

是禁止使用这种格式的代码的,标准格式应该是

和测试相关的函数
这个up解释的非常好,使用maven方式构建spring项目。在test里面创建了一个main方法测试IOC的基本使用。但是运行时候报错
快速解决方法,把他放进java,文件下去使用(用完之后删除,可以减少打包负担),要么按照up的方法改成test方法的函数,而不是main方法

4.1
如果mapper类上,没有注解,要在启动类上加一个扫描注解


5.写接口
注意返回数据是json用@RestController注解

5.1写一个结果返回类 或者叫做公共响应类

注解意思
@Data 生成get set 方法
@NoArgsConstructor 生成 无参构造方法
@AllArgsConstructor 生成 有参构造方法
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
private Integer code;
private String message;
private T data;
//封装 成功时返回的东西
public static <T> Result<T> success(){
return new Result<>(20000,"success",null);
}
//重载
public static <T> Result<T> success(T data){
return new Result<>(20000,"success",data);
}
//重载
public static <T> Result<T> success(T data,String message){
return new Result<>(20000,message,data);
}
//重载
public static <T> Result<T> success(String message){
return new Result<>(20000,message,null);
}
//失败时
public static<T> Result<T> fail(){
return new Result<>(20001,"fail",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);
}
public static<T> Result<T> fail( String message){
return new Result<>(20001,message,null);
}
}
5.2 使用mybatis-plus的分页查询,要先配置mybatis-plus拦截器
@Configuration
public class MpConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
5.3登录接口

controller
注意:这里可以先写controller层,虽然 service的login没写会报错,不用管,报错之后可以快速定位到没写的地方,可以直接生成代码架构然后再补充,更加方便
@PostMapping("/login")
public Result<Map<String,Object>> login(@RequestBody User user){
Map<String,Object> data = userService.login(user);
if(data != null){
return Result.success(data);
}
return Result.fail(20002,"用户名或密码错误");
}
service
public Map<String, Object> login(User user) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper();
wrapper.eq(User::getUsername,user.getUsername());
wrapper.eq(User::getPassword,user.getPassword());
User loginUser = this.getOne(wrapper);
if(loginUser != null){
Map<String, Object> data = new HashMap<>();
String key = "user::" + UUID.randomUUID();
data.put("token", key); // 待优化,最终方案jwt
loginUser.setPassword(null);
redisTemplate.opsForValue().set(key,loginUser,30, TimeUnit.MINUTES);
return data;
}
return null;
}
6.整合redis
- pom
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- yml
spring:
redis:
host: localhost
port: 6379
- 配置类
@Configuration
public class MyRedisConfig {
@Resource
private RedisConnectionFactory factory;
@Bean
public RedisTemplate redisTemplate(){
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
redisTemplate.setValueSerializer(serializer);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
om.setTimeZone(TimeZone.getDefault());
om.configure(MapperFeature.USE_ANNOTATIONS, false);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance ,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
om.setSerializationInclusion(JsonInclude.Include.NON_NULL);
serializer.setObjectMapper(om);
return redisTemplate;
}
}
7.获取用户信息

controller
@GetMapping("/info")
public Result<?> getUserInfo(@Param("token") String token){
Map<String,Object> data = userService.getUserInfo(token);
if(data != null){
return Result.success(data);
}
return Result.fail(20003,"用户信息获取失败");
}
service
public Map<String, Object> getUserInfo(String token) {
// 从redis查询token
Object obj = redisTemplate.opsForValue().get(token);
// 反序列化
User user = JSON.parseObject(JSON.toJSONString(obj),User.class);
if(user != null){
Map<String, Object> data = new HashMap<>();
data.put("name",user.getUsername());
data.put("avatar",user.getAvatar());
List<String> roleList = this.getBaseMapper().getRoleNamesByUserId(user.getId());
data.put("roles", roleList);
return data;
}
return null;
}
mapper.xml
<select id="getRoleNamesByUserId" parameterType="Integer" resultType="String">
SELECT
b.role_name
FROM x_user_role a,x_role b
WHERE a.`user_id` = #{userId}
AND a.`role_id` = b.`role_id`
</select>
8.注销

controller
@PostMapping("/logout")
public Result<?> logout(@RequestHeader("X-Token") String token){
userService.logout(token);
return Result.success("注销成功");
}
service
public void logout(String token) {
redisTemplate.delete(token);
}
9.跨域处理
这里注意,前后端都有跨域的处理方案,而且只用一端就行
这里是后端
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter(){
//1.添加CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//1) 允许的域,不要写*,否则cookie就无法使用了
config.addAllowedOrigin("http://localhost:8888"); //这里填写请求的前端服务器
//2) 是否发送Cookie信息
config.setAllowCredentials(true);
//3) 允许的请求方式
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
// 4)允许的头信息
config.addAllowedHeader("*");
//2.添加映射路径,我们拦截一切请求
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
//3.返回新的CorsFilter.
return new CorsFilter(configSource);
}
}
10.用户管理接口

10.1查询用户列表
controller
@GetMapping("/list")
public Result<?> getUserListPage(@RequestParam(value = "username", required = false) String username,
@RequestParam(value = "phone", required = false) String phone,
@RequestParam("pageNo") Long pageNo,
@RequestParam("pageSize") Long pageSize) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper();
wrapper.eq(username != null, User::getUsername, username);
wrapper.eq(phone != null, User::getPhone, phone);
Page<User> page = new Page<>(pageNo, pageSize);
userService.page(page, wrapper);
Map<String, Object> data = new HashMap<>();
data.put("total", page.getTotal());
data.put("rows", page.getRecords());
return Result.success(data);
}
11.0分页拦截器
@Configuration
public class MpConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
12.删除用户的逻辑删除
只需要配置一下mybatis-plus就行
然后再在数据库列里加上一个表示数据就行,例如 列名叫 delete 数据有 1 和0
logic-delete-field: delete 这个是列名
logic-delete-value: 1 删除时的值是
logic-not-delete-value: 0 没删除的值是
mybatis-plus:
global-config:
db-config:
logic-delete-field: delete
logic-delete-value: 1
logic-not-delete-value: 0
12.Swagger整合
Swagger-UI可以动态地根据注解生成在线API文档。
3.0比2更只能不用单个加注解,直接全显示
注意:可能会被jwt拦截器拦截,建议可以设置放行,不过在测试的时候可以以直接关闭jwt的拦截器,就把嘴上面的注解注释就行,不测试时再打开
常用注解
@Api:用于修饰Controller类,生成Controller相关文档信息
@ApiOperation:用于修饰Controller类中的方法,生成接口方法相关文档信息
@ApiParam:用于修饰接口中的参数,生成接口参数相关文档信息
@ApiModelProperty:用于修饰实体类的属性,当实体类是请求参数或返回结果时,直接生成相关文档信息
整合步骤:
添加依赖
<!--Swagger文档工具-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
swagger配置类
@Configuration
@EnableOpenApi
@EnableWebMvc
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.mu"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("神盾局特工管理系统接口文档")
.description("全网最简单的SpringBoot+Vue前后端分离项目实战")
.version("1.0")
.contact(new Contact("qqcn", "http://www.qqcn.cn", "qqcn@aliyun.com"))
.build();
}
}
控制器根据需要添加swagger注解
测试:http://localhost:9999/swagger-ui/index.html
A1前端接口与后端关联调用流程
1首先前端写了一个点击按钮


2点击后调用
openEditUI函数

<script>
import userApi from "@/api/userManage";
export default {
data() {
return {
formLabelWidth: "130px",
userForm: {},
dialogFormVisible: false,
title: "",
total: 0,
searchModel: {
pageNo: 1,
pageSize: 10,
},
userList: [],
rules: {
username: [
{ required: true, message: "请输入用户名", trigger: "blur" },
{
min: 1,
max: 50,
message: "长度在 1 到 50 个字符",
trigger: "blur",
},
],
password: [
{ required: true, message: "请输入初始密码", trigger: "blur" },
{
min: 1,
max: 16,
message: "长度在 1 到 16 个字符",
trigger: "blur",
},
],
email: [{ required: true, message: "请输入电子邮件", trigger: "blur" }],
},
};
},
methods: {
saveUser() {
//触发验证
this.$refs.userFormRef.validate((valid) => {
if (valid) {
//如果验证成功数据提交给后台
//then(Response,回调后端返回的数据,前端已经把数据传给后端后,前端下一步该干什么
userApi.addUser(this.userForm).then((Response) => {
//成功提示
this.$message({
message: Response.message,
type: "success",
});
//关闭对话框
this.dialogFormVisible=false;
//刷新显示表格
this.getUserList();
});
} else {
console.log("error submit!!");
return false;
}
});
},
cleraForm() {
this.userForm = {};
this.$refs.userFormRef.clearValidate();
},
openEditUI(id) {
if (id==null) {
this.title = "新增用户";
}else{
this.title = "修改用户";
//根据用户id查询数据
userApi.getUserById(id).then(Response =>{
this.userForm=Response.data;
})
}
this.dialogFormVisible = true;
},
handleSizeChange(pageSize) {
this.searchModel.pageSize = pageSize;
this.getUserList();
},
handleCurrentChange(pageNo) {
this.searchModel.pageNo = pageNo;
this.getUserList();
},
getUserList() {
userApi.getUserList(this.searchModel).then((Response) => {
this.userList = Response.data.rows;
this.total = Response.data.total;
});
},
},
created() {
this.getUserList();
},
};
</script>
3前端输完数据,传给函数




userManage.js
import request from '@/utils/request'
export default {
getUserList(searchModel) {
return request({
url: '/user/list',
method: 'get',
params: {
pageNo: searchModel.pageNo,
pageSize: searchModel.pageSize,
username: searchModel.username,
phone: searchModel.phone
}
});
},
addUser(user) {
return request({
url: '/user',
method: 'post',
data: user
});
},
updateUser(user) {
return request({
url: '/user',
method: 'put',
data: user
});
},
getUserById(id) {
return request({
url:`/user/${id}`,
method: 'get'
});
},
}
&spm=1001.2101.3001.5002&articleId=134185291&d=1&t=3&u=08256442105e4f4cb43f1c8026c12107)
1762

被折叠的 条评论
为什么被折叠?



