這10個Spring錯誤你一定中過招!

幫助萬千Java學(xué)習(xí)者持續(xù)成長

B 站搜索:楠哥教你學(xué)Java
獲取更多優(yōu)質(zhì)視頻教程
錯誤一:太過關(guān)注底層
錯誤二:內(nèi)部結(jié)構(gòu) “泄露”
public class TopTalentEntity {private Integer id;private String name;public TopTalentEntity(String name) {this.name = name;}}
TopTalentEntity數(shù)據(jù)。返回TopTalentEntity實例可能很誘人,但更靈活的解決方案是創(chuàng)建一個新的類來表示 API 端點上的TopTalentEntity數(shù)據(jù)。public class TopTalentData {private String name;}
TopTalentEntity中添加一個 “password” 字段來存儲數(shù)據(jù)庫中用戶密碼的 Hash 值 —— 如果沒有TopTalentData之類的連接器,忘記更改服務(wù)前端,將會意外地暴露一些不必要的秘密信息。錯誤三:缺乏關(guān)注點分離
TopTalentData。public class TopTalentController {private final TopTalentRepository topTalentRepository;public List<TopTalentData> getTopTalent() {return topTalentRepository.findAll().stream().map(this::entityToData).collect(Collectors.toList());}private TopTalentData entityToData(TopTalentEntity topTalentEntity) {return new TopTalentData(topTalentEntity.getName());}}
TopTalentEntity實例檢索出來的TopTalentData的 List。TopTalentController實際上在此做了些事情;也就是說,它將請求映射到特定端點,從數(shù)據(jù)庫檢索數(shù)據(jù),并將從TopTalentRepository接收的實體轉(zhuǎn)換為另一種格式。一個“更干凈” 的解決方案是將這些關(guān)注點分離到他們自己的類中。看起來可能是這個樣子的:public class TopTalentController {private final TopTalentService topTalentService;public List<TopTalentData> getTopTalent() {return topTalentService.getTopTalent();}}public class TopTalentService {private final TopTalentRepository topTalentRepository;private final TopTalentEntityConverter topTalentEntityConverter;public List<TopTalentData> getTopTalent() {return topTalentRepository.findAll().stream().map(topTalentEntityConverter::toResponse).collect(Collectors.toList());}}public class TopTalentEntityConverter {public TopTalentData toResponse(TopTalentEntity topTalentEntity) {return new TopTalentData(topTalentEntity.getName());}}
錯誤四:缺乏異常處理或處理不當(dāng)
public class ErrorResponse {private Integer errorCode;private String errorMessage;}
@ExceptionHandler注解來完成(注解案例可見于第六章)。避免全局狀態(tài)
避免可變性
記錄關(guān)鍵數(shù)據(jù)
復(fù)用現(xiàn)存實現(xiàn)
錯誤六:不使用基于注解的驗證
@RequestMapping("/put")public void addTopTalent(@RequestBody TopTalentData topTalentData) {boolean nameNonExistentOrHasInvalidLength =Optional.ofNullable(topTalentData).map(TopTalentData::getName).map(name -> name.length() == 10).orElse(true);if (nameNonExistentOrInvalidLength) {// throw some exception}topTalentService.addTopTalent(topTalentData);}
public void addTopTalent( TopTalentData topTalentData) {topTalentService.addTopTalent(topTalentData);}public ErrorResponse handleInvalidTopTalentDataException(MethodArgumentNotValidException methodArgumentNotValidException) {// handle validation exception}// 此外,我們還必須指出我們想要在 TopTalentData 類中驗證什么屬性:public class TopTalentData {private String name;}
({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})(RetentionPolicy.RUNTIME)(validatedBy = { MyAnnotationValidator.class })public MyAnnotation {String message() default "String length does not match expected";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};int value();}public class MyAnnotationValidator implements ConstraintValidator<MyAnnotation, String> {private int expectedLength;public void initialize(MyAnnotation myAnnotation) {this.expectedLength = myAnnotation.value();}public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {return s == null || s.length() == this.expectedLength;}}
isValid方法中的s == null),如果這是屬性的附加要求,則使用@NotNull注解。public class TopTalentData {private String name;}
錯誤七:(依舊)使用基于xml的配置
@SpringBootApplication復(fù)合注解中做了聲明,如下所示:public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}
@Component(TopTalentConverter,MyAnnotationValidator)@RestController(TopTalentController)@Repository(TopTalentRepository)@Service(TopTalentService) 類
@Configuration注解類,它們也會檢查基于 Java 的配置。錯誤八:忽略 profile
APPLICATION.YAML 文件
# set default profile to 'dev'spring.profiles.active: dev# production database details# 公眾號:程序員追風(fēng)spring.datasource.url: 'jdbc:mysql://localhost:3306/toptal'spring.datasource.username: rootspring.datasource.password:8.2. APPLICATION-DEV.YAML 文件spring.datasource.url: 'jdbc:h2:mem:'spring.datasource.platform: h2
-Dspring.profiles.active=prod參數(shù)給 JVM 來手動覆蓋配置文件。另外,還可將操作系統(tǒng)的環(huán)境變量設(shè)置為所需的默認(rèn) profile。錯誤九:無法接受依賴項注入
public class TopTalentController {private final TopTalentService topTalentService;public TopTalentController() {this.topTalentService = new TopTalentService();}}
public class TopTalentController {private final TopTalentService topTalentService;public TopTalentController(TopTalentService topTalentService) {this.topTalentService = topTalentService;}}
TopTalentService行為正確的前提下測試控制器。我們可以通過提供一個單獨的配置類來插入一個模擬對象來代替實際的服務(wù)實現(xiàn):@Configurationpublic class SampleUnitTestConfig {public TopTalentService topTalentService() {TopTalentService topTalentService = Mockito.mock(TopTalentService.class);Mockito.when(topTalentService.getTopTalent()).thenReturn(Stream.of("Mary", "Joel").map(TopTalentData::new).collect(Collectors.toList()));return topTalentService;}}
SampleUnitTestConfig作為它的配置類來注入模擬對象:@ContextConfiguration(classes = { SampleUnitTestConfig.class })錯誤十:缺乏測試,或測試不當(dāng)
DispatcherServlet,并查看當(dāng)收到一個實際的HttpServletRequest時會發(fā)生什么(使它成為一個 “集成” 測試,處理驗證、序列化等)。@RunWith(SpringJUnit4Cla***unner.class)@ContextConfiguration(classes = {Application.class,SampleUnitTestConfig.class})public class RestAssuredTestDemonstration {@Autowiredprivate TopTalentController topTalentController;@Testpublic void shouldGetMaryAndJoel() throws Exception {// givenMockMvcRequestSpecification givenRestAssuredSpecification = RestAssuredMockMvc.given().standaloneSetup(topTalentController);// whenMockMvcResponse response = givenRestAssuredSpecification.when().get("/toptal/get");// thenresponse.then().statusCode(200);response.then().body("name", hasItems("Mary", "Joel"));}}
SampleUnitTestConfig類將TopTalentService的模擬實現(xiàn)連接到TopTalentController中,而所有的其他類都是通過掃描應(yīng)用類所在包的下級包目錄來推斷出的標(biāo)準(zhǔn)配置。RestAssuredMockMvc只是用來設(shè)置一個輕量級環(huán)境,并向/toptal/get端點發(fā)送一個GET請求。楠哥簡介
資深 Java 工程師,微信號 southwindss
《Java零基礎(chǔ)實戰(zhàn)》一書作者
騰訊課程官方 Java 面試官,今日頭條認(rèn)證大V
GitChat認(rèn)證作者,B站認(rèn)證UP主(楠哥教你學(xué)Java)
致力于幫助萬千 Java 學(xué)習(xí)者持續(xù)成長。

評論
圖片
表情
