Web后端开发_05
SpringBootWeb案例_02
1.新增员工
1.1需求
在新增用户时,我们需要保存用户的基本信息,并且还需要上传的员工的图片,目前我们先完成第一步操作,保存用户的基本信息。
1.2 接口文档
基本信息
请求路径:/emps
请求方式:POST
接口描述:该接口用于添加员工的信息
请求参数
参数格式:application/json
参数说明:
名称 | 类型 | 是否必须 | 备注 |
username | string | 必须 | 用户名 |
name | string | 必须 | 姓名 |
gender | number | 必须 | 性别, 说明: 1 男, 2 女 |
image | string | 非必须 | 图像 |
deptId | number | 非必须 | 部门id |
entrydate | string | 非必须 | 入职日期 |
job | number | 非必须 | 职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师 |
请求数据样例:
{
"image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-03-07-37-38222.jpg",
"username": "linpingzhi",
"name": "林平之",
"gender": 1,
"job": 1,
"entrydate": "2022-09-18",
"deptId": 1
}
响应数据
参数格式:application/json
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
code | number | 必须 | 响应码,1 代表成功,0 代表失败 |
msg | string | 非必须 | 提示信息 |
data | object | 非必须 | 返回的数据 |
响应数据样例:
{
"code":1,
"msg":"success",
"data":null
}
1.3思路
1.4功能开发
EmpController.java
@Slf4j
@RestController
@RequestMapping("/emps")
public class EmpController {
@Autowired
private EmpService empService;
@PostMapping
public Result save(@RequestBody Emp emp) {
log.info("新增员工,emp:{}", emp);
empService.save(emp);
return Result.success();
}
}
EmpService.java
public interface EmpService {
/**
* 新增员工
* @param emp
*/
void save(Emp emp);
}
EmpServiceImpl.java
@Service
public class EmpServiceImpl implements EmpService {
@Autowired
private EmpMapper empMapper;
@Override
public void save(Emp emp) {
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
empMapper.insert(emp);
}
}
EmpMapper.java
@Mapper
public interface EmpMapper {
/**
* 新增员工
* @param emp
*/
void insert(Emp emp);
}
EmpMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bowen.mapper.EmpMapper">
<insert id="insert">
insert into tlias.emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)
VALUES (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime},#{updateTime})
</insert>
</mapper>
1.5 功能测试
代码开发完成后,重启服务器,打开Postman发送 POST 请求,
请求路径:http://localhost:8080/emps
1.6 前后端联调
功能测试通过后,再进行通过打开浏览器,测试后端功能接口:
2.文件上传(阿里云OSS)
黑马程序员2023新版JavaWeb开发教程
(P146 Day11-02. 案例-文件上传-简介——P150 Day11-06. 案例-文件上传-阿里云OSS-集成)
2.1简介
- 文件上传,是指将本地图片、视频、音频等文件上传到服务器,供其他用户浏览或下载的过程。
- 文件上传在项目中应用非常广泛,例如发微博、发微信朋友圈都用到了文件上传功能
2.1.1前端页面三要素
- 表单项
file
-
post
方式(由于上传文件较大,所以使用post) - 编码格式
multipart/form-data
(默认编码格式不适用于传输大型的二进制数据文件)
upload.html
放在resources/static
目录下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传文件</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
姓名: <input type="text" name="username"><br>
年龄: <input type="text" name="age"><br>
头像: <input type="file" name="image"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
2.1.2服务端接收文件
UploadController.java
@Slf4j
@RestController
public class UploadController {
@PostMapping("/upload")
public Result upload(String username, Integer age, MultipartFile image) {
log.info("文件上传:{},{},{}", username, age, image);
return Result.success();
}
}
打断点进行调试
使用谷歌浏览器进行上传文件
可以看到生成的临时文件的路径
location C:\Users\1900\AppData\Local\Temp\tomcat.8080.6952090206307874716\work\Tomcat\localhost\ROOT
在文件资源管理器中打开该目录
将三个临时文件复制到一个桌面新建的文件夹中,并将其改名为1.txt
、2.txt
、3.txt
,用记事本打开三个文件,可以看到
放行断点,临时文件自动被删除,说明还需要在服务端写存储文件的方法
2.1.3小结
前端页面三要素
- 表单项
type= "file"
- 表单提交方式
post
(由于上传文件较大,所以使用post)- 表单的enctype属性
multipart/form-data
(默认编码格式不适用于传输大型的二进制数据文件)服务端接收文件
MultipartFile
2.2本地存储
在服务端,接收到上传上来的文件之后,将文件存储在本地服务器磁盘中。
UploadController.java
上传文件的controller控制层
@Slf4j
@RestController
public class UploadController {
@PostMapping("/upload")
public Result upload(String username, Integer age, MultipartFile image) throws IOException {
log.info("文件上传:{},{},{}", username, age, image);
//获取原始文件名
String filename = image.getOriginalFilename();
//构建唯一的文件名(不能重复)- uuid(通用唯一识别码) 7e8c6178-3320-4638-b4d9-19de7cb733f4
int index = filename.lastIndexOf(".");
String extname = filename.substring(index);
String newFileName = UUID.randomUUID().toString() + extname;
//将文件存储在服务器的磁盘目录中 E:\images
image.transferTo(new File("E:\\images\\" + newFileName));
return Result.success();
}
}
测试UUID,演示UUID的生成
@SpringBootTest
class TliasWebManagementApplicationTests {
@Test
public void testUuid() {
for (int i = 0; i < 1000; i++) {
String uuid = UUID.randomUUID().toString();
System.out.println(uuid);
}
}
}
org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException: The field image exceeds its maximum permitted size of 1048576 bytes.
在SpringBoot中,文件上传,默认单个文件允许最大大小为1M。如果需要上传大文件,可以进行如下配置:
application.properties
#配置单个文件最大上传大小
spring.servlet.multipart.max-file-size=10MB
#配置单个请求最大上传大小(一次请求可以上传多个文件)
spring.servlet.multipart.max-request-size=100MB
测试上传文件
MultipartFile
提供的常见方法
String getOriginalFilename();
//获取原始文件名void transferTo(File dest);
//将接收的文件转存到磁盘文件中long getSize();
//获取文件的大小,单位:字节byte[] getBytes();
//获取文件内容的字节组数InputStream getInputStream();
//或缺接收到的文件内容的输入流
2.3阿里云OSS
阿里云是阿里巴巴集团旗下全球领先的云计算公司,也是国内最大的云服务提供商。
阿里云对象存储OSS ( object Storage Service),是一款海量、安全、低成本、高可靠的云存储服务。使用OSS,您可以通过网络随时存储和调用包括文本、图片、音频和视频等在内的各种文件。
2.3.1第三方服务-通用思路
2.3.2阿里云OSS-使用步骤
Bucket:存储空间是用户用于存储对象(Object,就是文件)的容器,所有的对象都必须隶属于某个存储空间。
SDK:Software Development Kit的缩写,软件开发工具包,包括辅助软件开发的依赖(jar包)、代码示例等,都可以叫做SDK。
2.3.2.1.注册阿里云
注册账号后需要实名认证,流程不在赘述。
2.3.2.2.充值
新账号可免费体验三个月OSS对象存储服务,40G的OSS资源包首年9¥,5年45¥
2.3.2.3.开通对象存储服务OSS
免费使用三个月对象存储OSS
2.3.2.4.创建Bucket
打开对象存储oss控制台
创建OSS Bucket空间
进入Bucket
Bucket空间长这样
2.3.2.5.获取AccessKey
创建AccessKey,请务必保存好AccessKey
2.3.2.6.参照官方SDK编写入门程序
打开阿里云SDK
看上传文件SDK
拷贝文件代码到src/test/java/com/bowen
文件夹中
对代码进行简单修改
测试的图片
测试结果
2.4阿里云OSS-集成
1.基本流程
步骤
- 引入阿里云OSS上传文件工具类(由官方的示例代码改造而来)
- 上传图片接口开发
2.AliOSSUtils.java
工具类
/**
* 阿里云 OSS 工具类
*/
@Component
public class AliOSSUtils {
private String endpoint = "地域节点";
private String accessKeyId = "AccessKey ID";
private String accessKeySecret = "AccessKey Secret";
private String bucketName = "存储空间名称";
/**
* 实现上传图片到OSS
*/
public String upload(MultipartFile file) throws IOException {
// 获取上传的文件的输入流
InputStream inputStream = file.getInputStream();
// 避免文件覆盖
String originalFilename = file.getOriginalFilename();
String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
//上传文件到 OSS
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
ossClient.putObject(bucketName, fileName, inputStream);
//文件访问路径
String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
// 关闭ossClient
ossClient.shutdown();
return url;// 把上传到oss的路径返回
}
}
3.UploadController.java
@Slf4j
@RestController
public class UploadController {
@Autowired
private AliOSSUtils aliOSSUtils;
//阿里云OSS
@PostMapping("/upload")
public Result upload(MultipartFile image) throws IOException {
log.info("文件上传,文件名:{}",image.getOriginalFilename());
String url = aliOSSUtils.upload(image);//调用阿里云OSS工具类,将上传来的文件存入阿里云
log.info("文件上传完成,文件访问的url:{}",url);
return Result.success(url);//将图片上传完成的url返回,用于浏览器回显展示
}
}
4.API测试
5.前端联调,新增员工
我这个前端好像有一丢丢问题
6.查看数据库保存的url
2.5小结
- 文件上床介绍
- 前端页面三要素(file表单项、post方式、multipart/form-data)
- 服务端接收文件(MultipartFile)
- 文件存储方式
- 本地存储(问题:无法直接访问、磁盘空间限制、磁盘损坏)
- 云存储OSS
3.修改员工
3.1需求
3.2查询回显
3.2.1接口文档
根据ID查询
基本信息
请求路径:/emps/{id}
请求方式:GET
接口描述:该接口用于根据主键ID查询员工的信息
请求参数
参数格式:路径参数
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
id | number | 必须 | 员工ID |
请求参数样例:
/emps/1
响应数据
参数格式:application/json
参数说明:
名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
code | number | 必须 | 响应码, 1 成功 , 0 失败 | ||
msg | string | 非必须 | 提示信息 | ||
data | object | 必须 | 返回的数据 | ||
|- id | number | 非必须 | id | ||
|- username | string | 非必须 | 用户名 | ||
|- name | string | 非必须 | 姓名 | ||
|- password | string | 非必须 | 密码 | ||
|- entrydate | string | 非必须 | 入职日期 | ||
|- gender | number | 非必须 | 性别 , 1 男 ; 2 女 | ||
|- image | string | 非必须 | 图像 | ||
|- job | number | 非必须 | 职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师 | ||
|- deptId | number | 非必须 | 部门id | ||
|- createTime | string | 非必须 | 创建时间 | ||
|- updateTime | string | 非必须 | 更新时间 |
响应数据样例:
{
"code": 1,
"msg": "success",
"data": {
"id": 2,
"username": "zhangwuji",
"password": "123456",
"name": "张无忌",
"gender": 1,
"image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-02-00-27-53B.jpg",
"job": 2,
"entrydate": "2015-01-01",
"deptId": 2,
"createTime": "2022-09-01T23:06:30",
"updateTime": "2022-09-02T00:29:04"
}
}
3.2.2思路
3.2.3实现
EmpController.java
控制层
@Slf4j
@RestController
@RequestMapping("/emps")
public class EmpController {
@Autowired
private EmpService empService;
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id) {
log.info("根据ID查询员工信息:{}", id);
Emp emp = empService.getById(id);
return Result.success(emp);
}
}
EmpServiceImpl.java
员工 接口的实现类
@Service
public class EmpServiceImpl implements EmpService {
@Autowired
private EmpMapper empMapper;
@Override
public Emp getById(Integer id) {
return empMapper.getById(id);
}
}
EmpService.java
接口
public interface EmpService {
/**
* 根据id查询员工
*
* @param id
* @return
*/
Emp getById(Integer id);
}
EmpMapper.java
员工的Mapper层,由于SQL语句比较简单,直接用注解@Select
@Mapper
public interface EmpMapper {
/**
* 根据ID查询员工
*
* @param id
* @return
*/
@Select("select * from emp where id = #{id};")
Emp getById(@Param("id") Integer id);
}
3.2.4API测试
3.2.5前端联调
3.3修改员工
3.3.1需求
查询到回显数据后,需要修改信息
3.3.2接口文档
基本信息
请求路径:/emps
请求方式:PUT
接口描述:该接口用于修改员工的数据信息
请求参数
参数格式:application/json
参数说明:
名称 | 类型 | 是否必须 | 备注 |
id | number | 必须 | id |
username | string | 必须 | 用户名 |
name | string | 必须 | 姓名 |
gender | number | 必须 | 性别, 说明: 1 男, 2 女 |
image | string | 非必须 | 图像 |
deptId | number | 非必须 | 部门id |
entrydate | string | 非必须 | 入职日期 |
job | number | 非必须 | 职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师 |
请求数据样例:
{
"id": 1,
"image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-03-07-37-38222.jpg",
"username": "linpingzhi",
"name": "林平之",
"gender": 1,
"job": 1,
"entrydate": "2022-09-18",
"deptId": 1
}
响应数据
参数格式:application/json
参数说明:
参数名 | 类型 | 是否必须 | 备注 |
code | number | 必须 | 响应码,1 代表成功,0 代表失败 |
msg | string | 非必须 | 提示信息 |
data | object | 非必须 | 返回的数据 |
响应数据样例:
{
"code":1,
"msg":"success",
"data":null
}
3.3.3思路
3.3.4实现
EmpController.java
控制层
@Slf4j
@RestController
@RequestMapping("/emps")
public class EmpController {
@Autowired
private EmpService empService;
@PutMapping
public Result update(@RequestBody Emp emp){
log.info("更新员工信息,emp:{}", emp);
empService.update(emp);
return Result.success();
}
}
EmpServiceImpl.java
员工 接口的实现类
@Service
public class EmpServiceImpl implements EmpService {
@Autowired
private EmpMapper empMapper;
@Override
public void update(Emp emp) {
emp.setUpdateTime(LocalDateTime.now());
empMapper.update(emp);
}
}
EmpService.java
接口
public interface EmpService {
/**
* 更新员工数据
* @param emp
*/
void update(Emp emp);
}
EmpMapper.java
员工的Mapper层
@Mapper
public interface EmpMapper {
/**
* 更新员工
* @param emp
*/
void update(Emp emp);
}
EmpMapper.xml
由于要动态SQL,所以在xml文件中写SQL语句
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bowen.mapper.EmpMapper">
<!--更新员工-->
<update id="update">
update emp
<set>
<if test="username != null and username != ''">
username = #{username},
</if>
<if test="password != null and password != ''">
password = #{password},
</if>
<if test="name != null and name != ''">
name=#{name},
</if>
<if test="gender != null">
gender=#{gender},
</if>
<if test="image != null and image !=''">
image=#{image},
</if>
<if test="job != null">
job=#{job},
</if>
<if test="entrydate != null">
entrydate=#{entrydate},
</if>
<if test="deptId != null">
dept_id=#{deptId},
</if>
<if test="updateTime != null">
update_time=#{updateTime}
</if>
</set>
where id = #{id};
</update>
</mapper>
3.3.5API调试
3.3.6前端联调
可以看到修改成功!!!
4.配置文件
4.1参数配置化
4.1.1问题分析
项目中的参数配置过于分散,不方便集中的管理和维护
自定义的阿里云OSS配置信息application.properties
冷知识:alt + 鼠标左键 可以同时编辑多行
-
@value
注解通常用于外部配置的属性注入,具体用法为:@Value("${配置文件中的key)")
4.2yml配置文件
- SpringBoot提供了多种属性配置方式
application.properties
server.port=8080
server.address=127.0.0.1
application.yml
server:
port: 9000
address: 127.0.0.1
application.yaml
server:
port: 9000
address: 127.0.0.1
- 常见配置文件格式对比
4.3yml基本语法
- 大小写敏感
- 数值前边必须有空格,作为分隔符
- 使用缩进表示层级关系,缩进时,不允许使用Tab键,只能用空格(idea中会自动将Tab转换为空格)缩进的空格
- 数目不重要,只要相同层级的元素左侧对齐即可
- #表示注释,从这个字符一直到行尾,都会被解析器忽略
4.4yml数据格式
- 对象/Map集合
user:
name: zhangsan
age: 18
password: 123456
- 数组/List/Set集合
hobby:
- java
- game
- sport
4.5yml配置
- 在
application.yml
中的配置案例相关的配置项
#端口配置
server:
port: 8080
#mybatis的配置
mybatis:
mapper-locations: classpath:mappers/*xml
type-aliases-package: com.bowen.mybatis.entity
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
spring:
#数据库连接信息
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/tlias
username: root
password: 密码
#文件上传的配置
servlet:
multipart:
max-file-size: 10MB
max-request-size: 100MB
#阿里云配置
aliyun:
oss:
endpoint: 地域节点
accessKeyId: AccessKey ID
accessKeySecret: AccessKey Secret
bucketName: 存储空间名称
4.6@ConfigurationProperties
4.6.1问题分析
4.6.2解决方案
使用@ConfigurationProperties
注解,前提:配置文件中key的名字=实体类中的属性名
在utils下创建AliOSSProperties.java
阿里云OSS的实体类
@Data
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSProperties {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
}
重新编写AliOSSUtils.java
中的代码
@Component
public class AliOSSUtils {
@Autowired
private AliOSSProperties aliOSSProperties;
/**
* 实现上传图片到OSS
*/
public String upload(MultipartFile file) throws IOException {
//获取阿里云OSS参数
String endpoint = aliOSSProperties.getEndpoint();
String accessKeyId = aliOSSProperties.getAccessKeyId();
String accessKeySecret = aliOSSProperties.getAccessKeySecret();
String bucketName = aliOSSProperties.getBucketName();
// 获取上传的文件的输入流
InputStream inputStream = file.getInputStream();
// 避免文件覆盖
String originalFilename = file.getOriginalFilename();
String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
//上传文件到 OSS
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
ossClient.putObject(bucketName, fileName, inputStream);
//文件访问路径
String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
// 关闭ossClient
ossClient.shutdown();
return url;// 把上传到oss的路径返回
}
}
4.6.3解决警告
在pom.xml
文件中配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
引入依赖后可以看到灰色的提示
在application.yml
中配置aliyun也有了提示信息
@ConfigurationProperties
与@Value
区别
相同点
- 都是用来注入外部配置的属性的
不通点
@Value
注解只能一个一个的进行外部属性的注入
String originalFilename = file.getOriginalFilename();
String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
//上传文件到 OSS
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
ossClient.putObject(bucketName, fileName, inputStream);
//文件访问路径
String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
// 关闭ossClient
ossClient.shutdown();
return url;// 把上传到oss的路径返回
}
}
解决警告
在pom.xml
文件中配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
引入依赖后可以看到灰色的提示
在application.yml
中配置aliyun也有了提示信息
4.7@ConfigurationProperties
与@Value
区别
相同点
- 都是用来注入外部配置的属性的
不同点
@Value
注解只能一个一个的进行外部属性的注入@ConfigurationProperties
可以批量的将外部的属性配置注入到bean对象的属性中