前言
建立一個全新的專案,或者把舊的龐大的專案,進行拆分成多個專案,在建立新的專案中,經常需要做一些重復的作業,比如說拷貝一下常用的工具類,通用代碼等等,所以就可以做一個基礎的專案方便使用,在經歷新專案的時候,直接在基礎專案上進行簡單配置就可以開發業務代碼了,
基礎專案該包含哪些東西,
Swagger在線介面檔案,
CodeGenerator 代碼生成器,
統一回傳,
通用的分頁物件,
常用工具類,
全域例外攔截,
錯誤列舉,
自定義例外,
多環境組態檔,
Maven多環境配置,
日志配置,
JenkinsFile,
Swagger
寫介面檔案通常是一件比較頭疼的事情,然而swagger就用是用來幫我們解決這個問題的,可以在線生成介面檔案,并且可以在頁面上進行測驗,

可以非常清楚的顯示,請求資料已經回應資料,當然這一切都需要在代碼中進行配置,

注意的點:介面檔案只能在測驗/開發環境開啟,其他環境請關閉,
常用的Swagger注解
@Api用于Controller
@ApiOperation用于Controller內的方法,
@ApiResponses用于標識介面回傳資料的型別,
@ApiModel用于標識類的名稱
@ApiModelProperty用于標識屬性的名稱
案例
@RestController
@Api(tags = "用戶")
@AllArgsConstructor
@RequestMapping("/user")
public class UserController {
private IUserService userService;
@ApiOperation("獲取用戶串列")
@GetMapping("/listUser")
@ApiResponses(
@ApiResponse(code = 200, message = "操作成功", response = UserVo.class)
)
public ResultVo listUser(@Validated ListUserForm listUserForm){
return ResultVoUtil.success(userService.listUser(listUserForm));
}
}
@Data
@ApiModel("獲取用戶串列需要的表單資料")
@EqualsAndHashCode(callSuper = false)
public class ListUserForm extends PageForm<ListUserForm> {
@ApiModelProperty("用戶狀態")
@NotEmpty(message = "用戶狀態不能為空")
@Range(min = -1 , max = 1 , message = "用戶狀態有誤")
private String status;
}
對應的swagger的配置可以查看基礎專案內的SwaggerConfiguration.java.
CodeGenerator代碼生成器,
mybatis_plus代碼生成器可以幫我們生成
entity,service,serviceImpl,mapper,mapper.xml,省去了建立一大堆物體類的麻煩,
由于配置太長這里就不貼出來了,對應的CodeGenerator的配置可以查看基礎專案內的CodeGenerator.java.
常用的封裝
統一回傳 ResultVo
將所有的介面的回應資料的格式進行統一,
@Data
@ApiModel("固定回傳格式")
public class ResultVo {
@ApiModelProperty("錯誤碼")
private Integer code;
@ApiModelProperty("提示資訊")
private String message;
@ApiModelProperty("回應資料")
private Object data;
}
抽象表單 BaseForm
public abstract class BaseForm<T> {
public abstract T buildEntity();
}
有小伙伴可能有疑問了,這個類有啥用呢,先看一下,下面的代碼,
@Override
public boolean addUser(AddUserForm userForm) {
User user = new User();
user.setNickname(userForm.getNickname());
user.setBirthday(userForm.getBirthday());
user.setUsername(userForm.getUsername());
user.setPassword(userForm.getPassword());
return save(user);
}
重構一下,感覺清爽了一些,
@Override
public boolean addUser(AddUserForm userForm) {
User user = new User();
BeanUtils.copyProperties(this,user);
return save(user);
}
使用BaseForm進行重構 AddUserForm 繼承 BaseForm并重寫buildEntity
@Data
@EqualsAndHashCode(callSuper = false)
public class AddUserForm extends BaseForm<User> {
private String nickname;
private Date birthday;
private String username;
private String password;
@Override
public User buildEntity() {
User user = new User();
BeanUtils.copyProperties(this,user);
return user;
}
}
@Override
public boolean addUser(AddUserForm userForm) {
return save(userForm.buildEntity());
}
上面的代碼有沒有種似曾相識的感覺,很多情況都是將接受到的引數,轉變成對應的物體類然后保存或者更新,所以對于這類的form可以繼承baseform并實作buildEntity()這樣可以更加符合面向物件,service不需要關心form如何轉變成entity,只需要在使用的時候呼叫buildEntity()即可,尤其是在form -> entity相對復雜的時候,這樣做可以減少service內的代碼,讓代碼邏輯看起來更加清晰,
通用的分頁物件
涉及到查詢的時候,絕大多數都需要用到分頁,所以說封裝分頁物件就很有必要,可以注意下PageForm.calcCurrent()、PageVo.setCurrentAndSize()、PageVo.setTotal()這個幾個方法,
PageForm
@Data
@ApiModel(value = "https://www.cnblogs.com/rutaha/archive/2021/01/27/分頁資料", description = "分頁需要的表單資料")
public class PageForm<T extends PageForm<?>>{
@ApiModelProperty(value = "https://www.cnblogs.com/rutaha/archive/2021/01/27/頁碼 從第一頁開始 1")
@Min(value = https://www.cnblogs.com/rutaha/archive/2021/01/27/1, message ="頁碼輸入有誤")
private Integer current;
@ApiModelProperty(value = "https://www.cnblogs.com/rutaha/archive/2021/01/27/每頁顯示的數量 范圍在1~100")
@Range(min = 1, max = 100, message = "每頁顯示的數量輸入有誤")
private Integer size;
@ApiModelProperty(hidden = true)
public T calcCurrent(){
current = (current - 1 ) * size;
return (T) this;
}
}
PageVo
@Data
public class PageVo<T> {
@ApiModelProperty(value = "https://www.cnblogs.com/rutaha/archive/2021/01/27/分頁資料")
private List<T> records;
@ApiModelProperty(value = "https://www.cnblogs.com/rutaha/archive/2021/01/27/總條數")
private Integer total;
@ApiModelProperty(value = "https://www.cnblogs.com/rutaha/archive/2021/01/27/總頁數")
private Integer pages;
@ApiModelProperty(value = "https://www.cnblogs.com/rutaha/archive/2021/01/27/當前頁")
private Integer current;
@ApiModelProperty(value = "https://www.cnblogs.com/rutaha/archive/2021/01/27/查詢數量")
private Integer size;
@ApiModelProperty(hidden = true)
public PageVo<T> setCurrentAndSize(PageForm<?> pageForm){
BeanUtils.copyProperties(pageForm,this);
return this;
}
@ApiModelProperty(hidden = true)
public void setTotal(Integer total) {
this.total = total;
this.setPages(this.total % this.size > 0 ? this.total / this.size + 1 : this.total / this.size);
}
}
案例
ListUserForm
@Data
@ApiModel("獲取用戶串列需要的表單資料")
@EqualsAndHashCode(callSuper = false)
public class ListUserForm extends PageForm<ListUserForm> {
@ApiModelProperty("用戶狀態")
@NotEmpty(message = "用戶狀態不能為空")
@Range(min = -1 , max = 1 , message = "用戶狀態有誤")
private String status;
}
UserServiceImpl
@Override
public PageVo<UserVo> listUser(ListUserForm listUserForm) {
PageVo<UserVo> pageVo = new PageVo<UserVo>().setCurrentAndSize(listUserForm);
pageVo.setTotal(countUser(listUserForm.getStatus()));
pageVo.setRecords(userMapper.listUser(listUserForm.calcCurrent()));
return pageVo;
}
private Integer countUser(String status){
return count(new QueryWrapper<User>().eq("status",status));
}
UserController
@ApiOperation("獲取用戶串列")
@GetMapping("/listUser")
@ApiResponses(
@ApiResponse(code = 200, message = "操作成功", response = UserVo.class)
)
public ResultVo listUser(@Validated ListUserForm listUserForm){
return ResultVoUtil.success(userService.listUser(listUserForm));
}

注意的點
PageVo在實體化的時候需要設定當前頁和每頁顯示的數量 可以呼叫setCurrentAndSize()完成,
進行分頁查詢的時候,需要計算偏移量,listUserForm.calcCurrent()
為什么要計算偏移量呢?
假如查詢第1頁每頁顯示10條記錄,前端傳遞過來的引數是current=1&&size=10,這個時候limit 1,10沒有問題,
假如查詢第2頁每頁顯示10條記錄,前端傳遞過來的引數是current=2&&size=10,這個時候limit 2,10就有問題,實際應該是limit 10,10,calcCurrent()的作用就是如此,
為什么不用MybatisPlus自帶的分頁插件呢?
自帶的分頁查詢在大量資料下,會出現性能問題,
常用工具類
常用工具類可以根據自己的開發習慣引入,
例外處理
例外處理的大致流程主要如下,
例外資訊拋出 -> ControllerAdvice 進行捕獲格式化輸出內容
手動拋出CustomException并傳入ReulstEnum ——> 進行捕獲錯誤資訊輸出錯誤資訊,
自定義例外
@Data
@EqualsAndHashCode(callSuper = false)
public class CustomException extends RuntimeException {
private final Integer code;
private final String method;
public CustomException(ResultEnum resultEnum, String method) {
super(resultEnum.getMsg());
this.code = resultEnum.getCode();
this.method = method;
}
public CustomException(Integer code, String message, String method) {
super(message);
this.code = code;
this.method = method;
}
}
錯誤資訊列舉
根據業務進行添加,
@Getter
public enum ResultEnum {
UNKNOWN_EXCEPTION(100, "未知例外"),
ADD_ERROR(103, "添加失敗"),
UPDATE_ERROR(104, "更新失敗"),
DELETE_ERROR(105, "洗掉失敗"),
GET_ERROR(106, "查找失敗"),
;
private Integer code;
private String msg;
ResultEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public static ResultEnum getByCode(int code){
for (ResultEnum resultEnum : ResultEnum.values()) {
if(code == resultEnum.getCode()){
return resultEnum;
}
}
return null;
}
}
全域例外攔截
全域例外攔截是使用@ControllerAdvice進行實作,常用的例外攔截配置可以查看 GlobalExceptionHandling,
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandling {
@ExceptionHandler(value = https://www.cnblogs.com/rutaha/archive/2021/01/27/CustomException.class)
public ResultVo processException(CustomException e) {
log.error("位置:{} -> 錯誤資訊:{}", e.getMethod() ,e.getLocalizedMessage());
return ResultVoUtil.error(Objects.requireNonNull(ResultEnum.getByCode(e.getCode())));
}
@ResponseStatus(HttpStatus.OK)
@ExceptionHandler(Exception.class)
public ResultVo exception(Exception e) {
e.printStackTrace();
return ResultVoUtil.error(ResultEnum.UNKNOWN_EXCEPTION);
}
}
案例
Controller
@ApiOperation("洗掉用戶")
@DeleteMapping("/deleteUser/{id}")
public ResultVo deleteUser(@PathVariable("id") String id){
userService.deleteUser(id);
return ResultVoUtil.success();
}
Service
@Override
public void deleteUser(String id) {
if(!removeById(id)){
throw new CustomException(ResultEnum.DELETE_ERROR, MethodUtil.getLineInfo());
}
}
結果


將報錯代碼所在的檔案第多少行都列印出來,方便排查,
注意的點
所有手動拋出的錯誤資訊,都應在錯誤資訊列舉ResultEnum進行統一維護,不同的業務使用不同的錯誤碼,方便在報錯時進行分辨,快速定位問題,
多環境配置
SpringBoot多環境配置
對于一個專案來講基本都4有個環境dev,test,pre,prod,對于SpringBoot專案多建立幾個組態檔就可以了,然后啟動的時候可以通過配置spring.profiles.active 來選擇啟動的環境,

java -jar BasicProject.jar --spring.profiles.active=prod
Maven多環境配置
假如想在打包的時候動態指定環境,這個時候就需要借助Maven的xml來實作,
配置XML
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<activatedProperties>dev</activatedProperties>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<activatedProperties>test</activatedProperties>
</properties>
</profile>
<profile>
<id>pre</id>
<properties>
<activatedProperties>pre</activatedProperties>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<activatedProperties>prod</activatedProperties>
</properties>
</profile>
</profiles>
更改application.yml
spring:
profiles:
# 選擇環境
active: @activatedProperties@
使用案例
mvn clean package -P prod
mvn clean package -P pre
mvn clean package -P test
打包完可以解壓開查看application.yml 會發現spring.profiles.active=@activatedProperties@ 發生了改變,
日志配置
采用logback日志配置
JenkinsFile
JenkinsFile肯定顧名思義是給jenkins用的,主要是配置專案根據如何進行構建并發布到不同的環境,需要去了解pipeline語法,以及如何配置jenkins,
JenkinsFileDemo https://gitee.com/huangxunhui/basic_project/blob/master/Jenkinsfile
總結了一些2020年的面試題,這份面試題的包含的模塊分為19個模塊,分別是: Java基礎、容器、多執行緒、反射、物件拷貝、JavaWeb例外、網路、設計模式、Spring/SpringMVC、SpringBoot/SpringCloud、Hibernate、MyBatis、RabbitMQ、Kafka、Zookeeper、MySQL、Redis、JVM,
獲取以下資料,關注公眾號:【有故事的程式員】,
記得點個關注+評論哦~
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/253402.html
標籤:其他
上一篇:13K點贊都基于 Vue+Spring 前后端分離管理系統ELAdmin,大愛
下一篇:【java自學】基礎知識點筆記
