前言
如果根据之前做的 Nest.js 后端项目功能为标准的话,那么 Spring Boot 项目需要几种功能进行整合,好在生态丰富,集成也不算困难。所以打算根据之前的项目使用 Spring Boot 重写个新的项目:
- Restful API CRUD 功能实现
- 数据库对象关系映射功能持久化支持
- OpenAPI 文档支持
- 参数校验判断业务
- redis 缓存
- ...
数据库持久化支持
目前数据库持久化主要是 Spring Boot Jpa 和 Spring Boot Mybatis 。如果看过 JPA 的业务过程会发现和 Nodejs 中的 TypeORM 及其相似。Mybatis 主要可以灵活调试动态 Sql 。不管怎么说根据自己项目业务需求选定其中功能吧。
安装 MyBatis 教程可以官方文档查阅:mybatis-spring-boot-autoconfigure
Swagger 文档支持
集成 Swagger UI 文档支持也非常简单,生态中的 springfox 做的不错,添加依赖:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
这里需要指定版本,不指定拉取依赖会报错。
然后在启动方法添加注解:
@EnableOpenApi
public class YasuoApplication {
public static void main(String[] args) {
// ...
}
}
然后在 Controller 类上添加标识:
@Api(value = "global", tags = "全局接口")
@RestController
@RequestMapping("/")
public class AppController {
}
在然后在方法里添加详细信息:
@Api(value = "global", tags = "全局接口")
@RestController
@RequestMapping("/")
public class AppController {
UserService userService;
@ApiOperation(value = "用户登录", notes = "系统用户登录")
@PostMapping("login")
public JSONObject login(@RequestParam("username") String username, @RequestParam("password") String password) {
System.out.println(username);
System.out.println(password);
JSONObject info = new JSONObject();
return info;
}
}
启动项目访问:http://localhost:8080/swagger-ui 即可访问。值得注意是如果你在 application 添加 server.servlet.contextPath 选项的时候记得添加对应的字段。
参数校验 JSR303
从 springboot-2.3 开始,校验包被独立成了一个 starter 组件:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
比如在 DTO 类里:
package com.iiong.yasuo.dto;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
@Data
public class UserLoginRequestDTO {
@NotEmpty(message = "登录名称不得为空!")
private String username;
@NotEmpty(message = "登录密码不得为空!")
private String password;
}
内置的校验注解可以查看官方文档,然后进行参数校验:
@ApiOperation(value = "用户登录", notes = "系统用户登录")
@PostMapping("login")
public RestfulModel<UserLoginResponseDTO> login(@RequestBody @Validated UserLoginRequestDTO userLoginRequestDTO) {
System.out.println(userLoginRequestDTO);
UserLoginResponseDTO userLoginResponseDTO = new UserLoginResponseDTO();
userLoginResponseDTO.setId(1013401346173L);
userLoginResponseDTO.setLoginName("112233");
userLoginResponseDTO.setName("系统管理员");
userLoginResponseDTO.setToken("test");
return new RestfulModel<>(0, "登录成功!", userLoginResponseDTO);
}
不过默认返回的异常信息并不是很友好,需要再次简化,所以需要做个全局异常处理。如果需要可以使用 @RestControllerAdvice 注解来表示全局处理类:
@ControllerAdvice
public class ExceptionHandlerConfig {
@ExceptionHandler(value = BindException.class)
@ResponseBody
public RestfulModel<Object> validExceptionHandler(BindException bindException) {
String exceptionMsg = bindException.getBindingResult().getAllErrors().get(0).getDefaultMessage();
return new RestfulModel<>(1000, exceptionMsg, null);
}
}
当然这里面还可以处理一些系统级别的异常,自己抛出即可。
跨域解决
解决跨域问题也很简单,只需要实现接口 WebMvcConfigurer 重写方法即可:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry corsRegistry) {
corsRegistry.addMapping("
@Validated
@Controller
@RequestMapping("/mongo")
public class MongoUploadController {
private static Logger logger = LoggerFactory.getLogger(MongoUploadController.class);
@Autowired
private GridFsTemplate gridFsTemplate;
@Autowired
private MongoTemplate mongoTemplate;
private static final List<String> CONTENT_TYPES = Arrays.asList("image/gif", "image/jpeg", "image/jpg", "image/png");
@PostMapping("/upload")
public ResponseEntity<String> fileUpload(@RequestParam("file") MultipartFile file) {
try {
// 校验文件信息(文件类型,文件内容)
String originalFilename = file.getOriginalFilename();
if (StrUtil.isBlank(originalFilename)) {
return ResponseEntity.badRequest().body("参数错误");
}
String contentType = file.getContentType();
if (!CONTENT_TYPES.contains(contentType)) {
return ResponseEntity.badRequest().body("文件类型错误");
}
InputStream inputStream = file.getInputStream();
BufferedImage bufferedImage = ImageIO.read(inputStream);
if (ObjectUtil.isEmpty(bufferedImage)) {
return ResponseEntity.badRequest().body("文件内容错误");
}
// 文件重命名
String suffix = FileNameUtil.getSuffix(originalFilename);
String fileName = IdUtil.simpleUUID().concat(".").concat(suffix);
// 文件上传,返回ObjectId
ObjectId objectId = gridFsTemplate.store(inputStream, fileName, contentType);
return StrUtil.isBlank(String.valueOf(objectId)) ? ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("文件上传失败") : ResponseEntity.ok(String.valueOf(objectId));
} catch (IOException e) {
return ResponseEntity.badRequest().body("文件上传异常");
}
}
@GetMapping("/read")
public void queryFileByObjectId(@RequestParam("objectId") @NotBlank(message = "ObjectId不能为空") String objectId, HttpServletResponse response) {
// 根据objectId查询文件
GridFSFile file = gridFsTemplate.findOne(new Query(Criteria.where("_id").is(objectId)));
// 创建一个文件桶
GridFSBucket gridFsBucket = GridFSBuckets.create(mongoTemplate.getDb());
InputStream inputStream = null;
OutputStream outputStream = null;
try {
if (ObjectUtil.isNotNull(file)) {
// 打开下载流对象
GridFSDownloadStream fileStream = gridFsBucket.openDownloadStream(file.getObjectId());
// 创建girdFsResource,传入下载流对象,获取流对象
GridFsResource gridFsResource = new GridFsResource(file, fileStream);
// 写入输出流
inputStream = gridFsResource.getInputStream();
outputStream = response.getOutputStream();
byte[] bytes = new byte[1024];
if (inputStream.read(bytes) != -1) {
outputStream.write(bytes);
}
}
} catch (IOException e) {
logger.error("文件读取异常: {}", e.getMessage());
} finally {
IoUtil.close(outputStream);
IoUtil.close(inputStream);
}
}
@DeleteMapping("/remove")
public ResponseEntity<String> removeFileByObjectId(@RequestParam("objectId") @NotBlank(message = "ObjectId不能为空") String objectId) {
gridFsTemplate.delete(new Query(Criteria.where("_id").is(objectId)));
return ResponseEntity.ok("删除成功");
}
}
如果需要实现在浏览器页面下载此资源的功能,可结合js进行操作(文件类型根据具体业务需求而定)。主要实现代码如下所示:
downloadNotes(noteId) {
axios({
url: this.BASE_API + '/admin/mongo/file/query/' + noteId,
method: 'get',
responseType: 'arraybuffer',
params: { type: 'download' }
}).then(res => {
// type类型可以设置为文本类型,这里是pdf类型
const pdfUrl = window.URL.createObjectURL(new Blob([res.data], { type: `application/pdf` }))
const fname = noteId // 下载文件的名字
const link = document.createElement('a')
link.href = pdfUrl
link.setAttribute('download', fname)
document.body.appendChild(link)
link.click()
URL.revokeObjectURL(pdfUrl) // 释放URL 对象
})
}
以上就是Spring Boot 功能整合的实现的详细内容,更多关于Spring Boot 功能整合的资料请关注编程网其它相关文章!