Spring Boot 功能整合的實(shí)現(xiàn)
前言
如果根據(jù)之前做的 Nest.js 后端項(xiàng)目功能為標(biāo)準(zhǔn)的話,那么 Spring Boot 項(xiàng)目需要幾種功能進(jìn)行整合,好在生態(tài)豐富,集成也不算困難。所以打算根據(jù)之前的項(xiàng)目使用 Spring Boot 重寫(xiě)個(gè)新的項(xiàng)目:
- Restful API CRUD 功能實(shí)現(xiàn)
- 數(shù)據(jù)庫(kù)對(duì)象關(guān)系映射功能持久化支持
- OpenAPI 文檔支持
- 參數(shù)校驗(yàn)判斷業(yè)務(wù)
- redis 緩存
- ...
數(shù)據(jù)庫(kù)持久化支持
目前數(shù)據(jù)庫(kù)持久化主要是 Spring Boot Jpa 和 Spring Boot Mybatis 。如果看過(guò) JPA 的業(yè)務(wù)過(guò)程會(huì)發(fā)現(xiàn)和 Nodejs 中的 TypeORM 及其相似。Mybatis 主要可以靈活調(diào)試動(dòng)態(tài) Sql 。不管怎么說(shuō)根據(jù)自己項(xiàng)目業(yè)務(wù)需求選定其中功能吧。
安裝 MyBatis 教程可以官方文檔查閱:mybatis-spring-boot-autoconfigure
Swagger 文檔支持
集成 Swagger UI 文檔支持也非常簡(jiǎn)單,生態(tài)中的 springfox 做的不錯(cuò),添加依賴:
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency>
這里需要指定版本,不指定拉取依賴會(huì)報(bào)錯(cuò)。
然后在啟動(dòng)方法添加注解:
@EnableOpenApi
public class YasuoApplication {
public static void main(String[] args) {
// ...
}
}
然后在 Controller 類(lèi)上添加標(biāo)識(shí):
@Api(value = "global", tags = "全局接口")
@RestController
@RequestMapping("/")
public class AppController {
}
在然后在方法里添加詳細(xì)信息:
@Api(value = "global", tags = "全局接口")
@RestController
@RequestMapping("/")
public class AppController {
UserService userService;
@ApiOperation(value = "用戶登錄", notes = "系統(tǒng)用戶登錄")
@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;
}
}
啟動(dòng)項(xiàng)目訪問(wèn):http://localhost:8080/swagger-ui 即可訪問(wèn)。值得注意是如果你在 application 添加 server.servlet.contextPath 選項(xiàng)的時(shí)候記得添加對(duì)應(yīng)的字段。
參數(shù)校驗(yàn) JSR303
從 springboot-2.3 開(kāi)始,校驗(yàn)包被獨(dú)立成了一個(gè) starter 組件:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
比如在 DTO 類(lèi)里:
package com.iiong.yasuo.dto;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
/**
* Author: Jaxson
* Description: 請(qǐng)求用戶登錄參數(shù)
* Date: 2021-05-26
*/
@Data
public class UserLoginRequestDTO {
@NotEmpty(message = "登錄名稱不得為空!")
private String username;
@NotEmpty(message = "登錄密碼不得為空!")
private String password;
}
內(nèi)置的校驗(yàn)注解可以查看官方文檔,然后進(jìn)行參數(shù)校驗(yàn):
@ApiOperation(value = "用戶登錄", notes = "系統(tǒng)用戶登錄")
@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("系統(tǒng)管理員");
userLoginResponseDTO.setToken("test");
return new RestfulModel<>(0, "登錄成功!", userLoginResponseDTO);
}
不過(guò)默認(rèn)返回的異常信息并不是很友好,需要再次簡(jiǎn)化,所以需要做個(gè)全局異常處理。如果需要可以使用 @RestControllerAdvice 注解來(lái)表示全局處理類(lèi):
/**
* Author: Jaxson
* Description: 全局異常處理類(lèi)
* Date: 2021-05-26
*/
@ControllerAdvice
public class ExceptionHandlerConfig {
/**
* 統(tǒng)一處理參數(shù)校驗(yàn)異常
* @param bindException 捕捉到的異常
* @return 返回?cái)?shù)據(jù)
*/
@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);
}
}
當(dāng)然這里面還可以處理一些系統(tǒng)級(jí)別的異常,自己拋出即可。
跨域解決
解決跨域問(wèn)題也很簡(jiǎn)單,只需要實(shí)現(xiàn)接口 WebMvcConfigurer 重寫(xiě)方法即可:
/**
* Author: Jaxson
* Description: 運(yùn)行跨域
* Date: 2021-05-26
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry corsRegistry) {
corsRegistry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedHeaders(CorsConfiguration.ALL)
.allowedMethods(CorsConfiguration.ALL)
.allowCredentials(true)
.maxAge(3600); // 1小時(shí)內(nèi)不需要再預(yù)檢(發(fā)OPTIONS請(qǐng)求)
}
}
整合MongoDB實(shí)現(xiàn)文件上傳下載刪除
引入pom依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
配置yml
spring:
data:
mongodb:
host: *.*.*.*
username: ***
password: ***
database: ***
port: 27017
# 設(shè)置文件上傳的大小限制
servlet:
multipart:
max-file-size: 10MB
max-request-size: 50MB
上傳下載刪除
/**
* @author Mr.Horse
* @version 1.0
* @description: MongoDB的文件上傳、下載、刪除等基本操作(集合HuTool工具庫(kù))
* @date 2021/4/29 9:53
*/
@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");
/**
* MongoDB文件上傳(圖片上傳)
*
* @param file
* @return
*/
@PostMapping("/upload")
public ResponseEntity<String> fileUpload(@RequestParam("file") MultipartFile file) {
try {
// 校驗(yàn)文件信息(文件類(lèi)型,文件內(nèi)容)
String originalFilename = file.getOriginalFilename();
if (StrUtil.isBlank(originalFilename)) {
return ResponseEntity.badRequest().body("參數(shù)錯(cuò)誤");
}
String contentType = file.getContentType();
if (!CONTENT_TYPES.contains(contentType)) {
return ResponseEntity.badRequest().body("文件類(lèi)型錯(cuò)誤");
}
InputStream inputStream = file.getInputStream();
BufferedImage bufferedImage = ImageIO.read(inputStream);
if (ObjectUtil.isEmpty(bufferedImage)) {
return ResponseEntity.badRequest().body("文件內(nèi)容錯(cuò)誤");
}
// 文件重命名
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("文件上傳異常");
}
}
/**
* 根據(jù)ObjectId讀取文件并寫(xiě)入響應(yīng)流,頁(yè)面進(jìn)行進(jìn)行相關(guān)操作,可以進(jìn)行文件的下載和展示
*
* @param objectId
*/
@GetMapping("/read")
public void queryFileByObjectId(@RequestParam("objectId") @NotBlank(message = "ObjectId不能為空") String objectId, HttpServletResponse response) {
// 根據(jù)objectId查詢文件
GridFSFile file = gridFsTemplate.findOne(new Query(Criteria.where("_id").is(objectId)));
// 創(chuàng)建一個(gè)文件桶
GridFSBucket gridFsBucket = GridFSBuckets.create(mongoTemplate.getDb());
InputStream inputStream = null;
OutputStream outputStream = null;
try {
if (ObjectUtil.isNotNull(file)) {
// 打開(kāi)下載流對(duì)象
GridFSDownloadStream fileStream = gridFsBucket.openDownloadStream(file.getObjectId());
// 創(chuàng)建girdFsResource,傳入下載流對(duì)象,獲取流對(duì)象
GridFsResource gridFsResource = new GridFsResource(file, fileStream);
// 寫(xiě)入輸出流
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);
}
}
/**
* 根據(jù)ObjectId刪除文件
*
* @param objectId
* @return
*/
@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("刪除成功");
}
}
如果需要實(shí)現(xiàn)在瀏覽器頁(yè)面下載此資源的功能,可結(jié)合js進(jìn)行操作(文件類(lèi)型根據(jù)具體業(yè)務(wù)需求而定)。主要實(shí)現(xiàn)代碼如下所示:
downloadNotes(noteId) {
axios({
url: this.BASE_API + '/admin/mongo/file/query/' + noteId,
method: 'get',
responseType: 'arraybuffer',
params: { type: 'download' }
}).then(res => {
// type類(lèi)型可以設(shè)置為文本類(lèi)型,這里是pdf類(lèi)型
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 對(duì)象
})
}
以上就是Spring Boot 功能整合的實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Spring Boot 功能整合的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- SpringBoot整合Drools的實(shí)現(xiàn)步驟
- SpringBoot整合MongoDB的實(shí)現(xiàn)代碼
- SpringBoot整合Redisson的步驟(單機(jī)版)
- springboot整合RabbitMQ發(fā)送短信的實(shí)現(xiàn)
- Java基礎(chǔ)之SpringBoot整合knife4j
- SpringBoot整合MyBatis超詳細(xì)教程
- SpringBoot整合JDBC、Druid數(shù)據(jù)源的示例代碼
- SpringBoot整合EasyExcel實(shí)現(xiàn)文件導(dǎo)入導(dǎo)出
- SpringBoot整合MongoDB實(shí)現(xiàn)文件上傳下載刪除
- springboot cloud使用eureka整合分布式事務(wù)組件Seata 的方法
- springboot2.x只需兩步快速整合log4j2的方法
相關(guān)文章
springboot Interceptor攔截器excludePathPatterns忽略失效
這篇文章主要介紹了springboot Interceptor攔截器excludePathPatterns忽略失效的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
IDEA2020.1創(chuàng)建springboot項(xiàng)目(國(guó)內(nèi)腳手架)安裝lombok
這篇文章主要介紹了IDEA2020.1創(chuàng)建springboot項(xiàng)目(國(guó)內(nèi)腳手架)安裝lombok,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
IDEA設(shè)置生成帶注釋的getter和setter的圖文教程
通常我們用idea默認(rèn)生成的getter和setter方法是不帶注釋的,當(dāng)然,我們同樣可以設(shè)置idea像MyEclipse一樣生成帶有Javadoc的模板,具體設(shè)置方法,大家參考下本文2018-05-05
JAVA實(shí)現(xiàn)社會(huì)統(tǒng)一信用代碼校驗(yàn)的方法
這篇文章主要介紹了JAVA實(shí)現(xiàn)社會(huì)統(tǒng)一信用代碼校驗(yàn)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
Java中鎖的實(shí)現(xiàn)和內(nèi)存語(yǔ)義淺析
這篇文章主要給大家介紹了關(guān)于Java中鎖的實(shí)現(xiàn)和內(nèi)存語(yǔ)義的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11
JAVA區(qū)間值判斷[10,20)的實(shí)現(xiàn)
本文主要介紹了JAVA區(qū)間值判斷[10,20)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-09-09
Java中forEach使用lambda表達(dá)式,數(shù)組和集合的區(qū)別說(shuō)明
這篇文章主要介紹了Java中forEach使用lambda表達(dá)式,數(shù)組和集合的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07

