该笔记是记录听课的关于如何搭建Springboot的框架,以及使用mybatis-plus等技术实现一些常用功能如增删查改、文件的上传和下载、Excel的导入导出、图表的生成、怎么发邮件等。
文章目录
前言
此项目使用的是VUE+ELEMENTUI以及Springboot+mybatis-plus的技术进行的开发,基于IDEA软件。此笔记只记录了后端的开发,故此篇文章暂时只用到了Springboot+mybatis-plus的技术。
一、项目的构建
1.新建项目
①点击左边的Spring Initializr
②Server URL一般采用默认的镜像,但有时候可以使用阿里云的镜像,可以进行修改 ps:建议还是使用idea配套的资源,不建议修改
③给此项目进行取名,此项目取名为demo,并选择正确的路径
④Type选择Maven,JDK选择1.8,Java选择8
然后点击下一个
然后在此页面添加进需要的依赖
注意:此项目需要添加Lombok、Spring Web、MySQL Driver、Java Mail Sender(需要发送邮件就需要添加此功能)。然后右上角的Sprint Boot最好选择2.7.12版本
ps:如果想要选择Spring Boot 3以上的,JDK就得使用13/17以上?
Lombok的功能就是实现在实体的前面添加一个注解,就可以自动生成相关的get、set方法,而不用自己手动一个一个生成。
到此,项目创建完成。
2.构建数据库
此项目在mysql新建一个数据库2023test,并在数据库中新建了一个表admin。
分别有id(设为19位是因为mybatis可以自动生成19位的id);
is_delete设为逻辑删除位,有时候想要的选择的是逻辑上删除了的数据,但在数据库中是并未删除的数据;
3.项目配置
①配置application.properties
先点击resources/mapper/application.properties
编写添加一下代码:
#启动端口
server.port=8081
#数据库
spring.datasource.username= #自己数据库的账号
spring.datasource.password= #自己数据库的密码
spring.datasource.url=jdbc:mysql://localhost:3306/2023test #最后为数据库的名字
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# 时间格式化
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
#mybatis-plus日志,日志用于排查错误
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
mybatis-plus.mapper-locations=classpath:mapper/**.xml
如果想要实现像用户发送邮件的功能,则需要在最后继续添加代码:
#发邮件
spring.mail.host=smtp.qq.com
spring.mail.username=xxxxx@qq.com #发送者的邮箱
spring.mail.password=xxxxxx #发送者的授权码
spring.mail.protocol=smtp
spring.mail.port=587
spring.mail.default-encoding=utf-8
②添加并配置mybatis-plus
先在网上查找mybatis-plus
编写代码的时候,输入某变量的时候都选择baomiduo这个包,引入也是选择此包
将这一段复制到项目中的pom.xml
注意:添加至pom.xml中以后仍然报红,是因为有时候maven在复制代码进配置文件的时候自动下载依赖,但有时候需要手动进行刷新下载:点击右上角的maven,然后点击刷新即可
③生成架构
在test/java/com.example.demo的DemoApplicationTests类中的void contextLoads()方法中编写添加这段代码:
注意修改连接的用户名(普遍是root)、密码、数据库名字、两处路径、 builder.addInclude( "admin","xx","xxx")//数据库中有几个表此处就填写几个名称
String username = ""; //数据库名字
String password = "";
String url = "jdbc:mysql://localhost:3306/xxx"; //xxx为数据库名称
FastAutoGenerator.create(url, username, password)
.globalConfig(builder -> {
builder.author("xxx")//xxx为作者名字
.enableSwagger() // 开启swagger如果不想后面爱给删除报错,可以不开启swagger
.disableOpenDir() // 禁止打开文件夹
.commentDate("yyyy-MM-dd HH:mm:ss")
.dateType(DateType.ONLY_DATE)
.outputDir("D:\\IdeaProjects\\xxx\\src\\main\\java\\");
})//记得修改路径,其中的xxx为项目名称
.packageConfig(builder -> {
builder.parent("com")
.moduleName("example.demo")
.controller("controller")
.service("service")
.serviceImpl("service.Impl")
.entity("entity")
.mapper("mapper")
.xml("mapper.xml")
.other("utils")
.pathInfo(Collections.singletonMap(OutputFile.xml, "D:\\IdeaProjects\\xxx\\src\\main\\resources\\mapper"));//记得修改路径,其中的xxx为项目名称
})
.strategyConfig(builder -> {
builder.addInclude( "admin","xx","xxx")//数据库中有几个表此处就填写几个名称
.mapperBuilder()
.formatMapperFileName("%sMapper") // 格式化文件名
.formatXmlFileName("%sMapperXml") // 格式化文件名
.enableBaseResultMap()
.enableBaseColumnList()
.enableMapperAnnotation() // 开启 @Mapper 注解
.serviceBuilder()
.formatServiceFileName("%sService")
.formatServiceImplFileName("%sServiceImpl")
.entityBuilder()
.enableLombok() //开启 Lombok
.enableTableFieldAnnotation()
.versionColumnName("version")
.idType(IdType.ASSIGN_ID)
.logicDeleteColumnName("is_delete") //逻辑删除字段名
.naming(NamingStrategy.underline_to_camel) //数据库表映射到实体的命名策略:下划线转驼峰命
.columnNaming(NamingStrategy.underline_to_camel) //数据库表字段映射到实体的命名策略:下划线转驼峰命
.addTableFills(
new Column("version", FieldFill.INSERT),
new Column("is_delete", FieldFill.INSERT),
new Column("create_time", FieldFill.INSERT),
new Column("update_time", FieldFill.INSERT_UPDATE)
)
.controllerBuilder()
.formatFileName("%sController") //格式化 Controller 类文件名称,%s进行匹配表名,如 UserController
.enableRestStyle(); //开启生成 @RestController 控制器
})
.execute();
再在配置文件pom.xml处添加:
<!-- mybatis-plus代码生成-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.2</version>
</dependency>
<!-- 模板引擎 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
修改完成后点击代码左边的绿色按钮运行局部的代码:
运行后自动生成相应的架构:
二、编写增删查改的功能代码
1.编写功能前的准备
ps:功能代码在controller层编写,方法都在public class AdminController方法中实现
先生成Service层的对象
@Autowired //加此注解可以实现自动生成后面的new,下一行代码就不用写后面的=new xxx()
private AdminService adminService;
为了返回的对象一致,选择编写Result对象进行封装,增删查改通过调用Result来实现返回的信息。
①创建utils包:
②编写Result里面的代码:可以直接封装使用
package com.example.demo.utils;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
@Data
public class Result {
private Boolean success;
private Integer code;
private String message;
private Map<String, Object> data = new HashMap<String, Object>();
private long timestamp;
private Result() {
}
public static Result success() {
Result r = new Result();
r.setSuccess(true);
r.setCode(20000);
r.setMessage("执行成功");
r.setTimestamp(System.currentTimeMillis());
return r;
}
public static Result fail() {
Result r = new Result();
r.setSuccess(false);
r.setCode(50000);
r.setMessage("执行失败");
r.setTimestamp(System.currentTimeMillis());
return r;
}
public Result message(String message) {
this.setMessage(message);
return this;
}
public Result code(Integer code) {
this.setCode(code);
return this;
}
public Result data(String key, Object value) {
this.data.put(key, value);
return this;
}
}
2.添加用户
其中/xxxAdmin为路径,一般URL访问路径都是RequestMapping+PostMapping/GetMapping的路径。
@PostMapping("/insertAdmin") //使用POST是因为传入的是一个Admin对象
public Result insertAdmin(Admin admin){
boolean save = adminService.save(admin);
if(save){
return Result.success().message("添加成功");
}
return Result.fail().message("添加失败");
}
3.删除用户
@GetMapping("/deleteAdmin")//此处使用GET是因为只用传入id的参数就可以删除一个对象
public Result deleteAdmin(String id){
boolean flag = adminService.removeById(id);
if(flag){
return Result.success();
}
return Result.fail();
}
4.使用条件查询
@GetMapping("/selectAdmin")
public Result selectAdmin(){
QueryWrapper<Admin> adminQueryWrapper = new QueryWrapper<>();
//eq等于
adminQueryWrapper.eq("name","张三");
//like模糊查询
adminQueryWrapper.like("username","123");//采用的key=value的方式
//排序
adminQueryWrapper.orderByAsc("create_time");//一般新插入的数据在上面
List<Admin> list = adminService.list(adminQueryWrapper);
return Result.success().data("items",list);
}
/*此为没有条件的查找框架
public Result selectUsers(){
List<Admin> list = adminService.list();
return Result.success().data("items",list);
}
*/
ps:此为不规范的增删写法,因为后面查询返回的是一个集合,但是此处返回的是状态,结合在一起就会显得不那么正式
//此为不规范的写法,因为前面返回boolean后面又返回result
@PostMapping("/insertAdmin")
public Boolean insertAdmin(Admin admin){
boolean save = adminService.save(admin);
return save;
}
@GetMapping("/deleteUsers")
public Boolean deleteUsers(String id){
boolean b = adminService.removeById(id);
return b;
}
5.将查询条件封装为对象进行查询
封装为对象以后就避免了很多个参数一个个输入,可以直接输入一个参数对象,然后分别调用这个对象的属性就可以了。
package com.example.demo.entity.condition;
import lombok.Data;
@Data //自动生成getset方法
public class UsersCondition {
String name;
String number;
String phone;
String beginTime;
String endTime;
}
编写利用对象进行选择查询的方法:
//如果传入的参数是一个对象则需要在参数之前加上@RequestBody注解;Autowired自动注入
@Autowired
private UsersService usersService;
@PostMapping("/selectUsersByCondition")
public Result selectUserByCondition(@RequestBody UsersCondition usersCondition){
//如果传入的参数是一个对象则需要在参数之前加上@RequestBody注解
String name = usersCondition.getName();
String number = usersCondition.getNumber();
String phone = usersCondition.getPhone();
String beginTime = usersCondition.getBeginTime();
String endTime = usersCondition.getEndTime();
//构建查询条件
QueryWrapper<Users> usersQueryWrapper = new QueryWrapper<Users>();
if(!name.isEmpty()){
usersQueryWrapper.like("name",name);
}
if(!number.isEmpty()){
usersQueryWrapper.like("number",number);
}
if(!phone.isEmpty()){
usersQueryWrapper.like("phone",phone);
}
if (!beginTime.isEmpty() && !endTime.isEmpty()){
usersQueryWrapper.between("create_time",beginTime,endTime);
}
List<Users> list = usersService.list(usersQueryWrapper);
return Result.success().data("items",list);
}
6.使用分页查询进行查询
分页查询必须使用到当前页面和页面大小这两个参数
@RestController
@RequestMapping("/example.demo/users")
public class UsersController {
@Autowired
private UsersService usersService;
/* 分页查询 */
@PostMapping("/selectUsersByCondition")
public Result selectUsersByCondition(Long currentPage,Long pageSize){
//构造分页
Page<Users> usersPage = new Page<>(currentPage,pageSize);
//分页查询
Page<Users> page = usersService.page(usersPage);//某一页上有很多记录数
List<Users> records = page.getRecords();//获取一页上的记录
long total = page.getTotal();//记录的总数
return Result.success().data("items",records).data("total",total);
}
ps:一页里面有很多记录
还有一种参数传入的方式:此方法适用于get方式传参
// http://localhost:8080/name/age
// == http://localhost:8080/1/2
// 另一种参数方法: @PostMapping("/selectUsersByCondition/{currentPage}/{pageSize}")
public Result selectUsersByCondition(@PathVariable Long currentPage,@PathVariable Long pageSize){
分别对应每个参数的值,一定要在参数的前面加上注解@PathVariable,就会将相应值传给相应的参数
三、额外功能的实现
1.文件上传功能
文件上传使用post方式
/*上传文件*/
@PostMapping("/uploadFile")
public Result uploadFile(@RequestParam("file") MultipartFile multipartFile){
//根路径
String bassPath = "D:\\IdeaProjects\\demo\\src\\main\\resources\\files"; //基本路径
// 时间路径,格式化时间,以时间对文件夹进行分类
String dataPath = new SimpleDateFormat("YYYY\\MM\\dd").format(new Date());
//基本路径加上时间路径形成上传的文件夹,先创建文件夹再创建文件
String dirPath = bassPath +"\\"+ dataPath;
//System.out.println(dirPath);
File dirFile = new File(dirPath);//使用io的File
if(!dirFile.exists()){
boolean mkdirs = dirFile.mkdirs();
if(!mkdirs){//先创建文件夹再创建文件
return Result.fail().message("文件夹创建失败");
}
}
//originalname才是文件名,获取文件名
String originalFilename = multipartFile.getOriginalFilename();
if(originalFilename == null){
return Result.fail().message("文件名为空");
}
//对文件名通过"."进行分割 比如"文件.exe" => {"文件","exe"}
String[] fileName = originalFilename.split("\\.");
//每次上传的文件前面添加了随机值防止文件上传覆盖,通过UUID随机生成的字符串并且去除其中的横线,再加上文件类型组成完整的文件名
String targetFileName = UUID.randomUUID().toString().replace("-","") + "." + fileName[1];
File targetFile = new File(dirFile, targetFileName);
try(
InputStream inputStream = multipartFile.getInputStream();
OutputStream outputStream = Files.newOutputStream(targetFile.toPath());
){
byte[] buffer = new byte[1024];
int len = -1;
while ((len = inputStream.read(buffer)) != -1){ //拷贝,-1就表示已经读取完毕
outputStream.write(buffer,0,len);
}
}catch (Exception e){
return Result.fail().message("保存失败");
}
String path = targetFile.getPath();
return Result.success().data("url",path);
}
ps:为了避免重复上传导致覆盖问题,在文件名前面加随机数 UUID生成的随机字符串,就形成了每一个上传的文件都是不相同的
ps:使用postman进行上传文件测试
2.读写Excel表格功能
先添加Excel的依赖:此项目使用的是easyexcel
复制帮助文档里面的依赖到项目中:将版本修改为3.1.2
读取Excel里面的数据的方法:常用模板
3.发送邮件功能
首先在配置文件application.properties处有这几行代码:(上面已经编写了)
/*发送邮件*/
// @Autowired(required=false)
@Autowired
private JavaMailSender javaMailSender;
@GetMapping("/sendEmail/{target}")
public Result sendEmail(@PathVariable String target){
try{
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setFrom("xxxx@qq.com");//设置发送者的邮箱
simpleMailMessage.setTo(target);//设置发送邮件的目标对象
simpleMailMessage.setSubject("验证码");//设置发送邮件的主题
simpleMailMessage.setText("123456");//设置发送邮件的文本内容
javaMailSender.send(simpleMailMessage);
}catch (Exception e){
return Result.fail();
}
return null;
}
授权码的获取见此篇CSDN文章
结束语
浅浅记录一下师兄给我们讲解的后端框架的搭建以及一些常用功能的实现,也浅浅接触了Springboot+mybatis-plus技术