зеркало из
				https://github.com/iharh/notes.git
				synced 2025-10-31 05:36:08 +02:00 
			
		
		
		
	m
Этот коммит содержится в:
		
							родитель
							
								
									71f35a11de
								
							
						
					
					
						Коммит
						9b7ad5ddc6
					
				| @ -1,3 +1,6 @@ | |||||||
|  | https://github.com/IsmaelMartinez/teams-for-linux | ||||||
|  |     https://flathub.org/apps/com.github.IsmaelMartinez.teams_for_linux | ||||||
|  | 
 | ||||||
| https://techcommunity.microsoft.com/t5/microsoft-teams-blog/microsoft-teams-progressive-web-app-now-available-on-linux/ba-p/3669846 | https://techcommunity.microsoft.com/t5/microsoft-teams-blog/microsoft-teams-progressive-web-app-now-available-on-linux/ba-p/3669846 | ||||||
| 
 | 
 | ||||||
| chrome://apps | chrome://apps | ||||||
|  | |||||||
| @ -4,6 +4,8 @@ https://docs.axoniq.io/reference-guide/axon-framework/sagas/implementation | |||||||
| https://github.com/eventuate-tram/eventuate-tram-sagas | https://github.com/eventuate-tram/eventuate-tram-sagas | ||||||
| 
 | 
 | ||||||
| 2023 | 2023 | ||||||
|  | https://habr.com/ru/articles/744460/ | ||||||
|  |     axon | ||||||
| https://www.baeldung.com/cs/saga-pattern-microservices | https://www.baeldung.com/cs/saga-pattern-microservices | ||||||
|     https://www.vinsguru.com/choreography-saga-pattern-with-spring-boot/ |     https://www.vinsguru.com/choreography-saga-pattern-with-spring-boot/ | ||||||
|     https://www.vinsguru.com/orchestration-saga-pattern-with-spring-boot/ |     https://www.vinsguru.com/orchestration-saga-pattern-with-spring-boot/ | ||||||
|  | |||||||
							
								
								
									
										380
									
								
								pl/java/libfws/spring/boot/mvc/docs/courses/linkedin.txt
									
									
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										380
									
								
								pl/java/libfws/spring/boot/mvc/docs/courses/linkedin.txt
									
									
									
									
									
										Обычный файл
									
								
							| @ -0,0 +1,380 @@ | |||||||
|  | 2019 | ||||||
|  | https://www.linkedin.com/learning/spring-spring-mvc-2 | ||||||
|  |     Incoming HTTP Request is Processed by | ||||||
|  |         DispatcherServlet->HandlerMapping->Controller (Front Controller DP) | ||||||
|  |         ->Controller->...processing...->back-to-DispatcherServlet | ||||||
|  |         ->ViewResolver | ||||||
|  |          | ||||||
|  |     Instead of String method at Controller we can use | ||||||
|  |         ModelAndView | ||||||
|  |             .setViewName | ||||||
|  |             .setStatus | ||||||
|  |             .addObject(name, value) | ||||||
|  |     SearchController { | ||||||
|  |         @GetMapping("/search") | ||||||
|  |         public String search(@RequestParam("search") String search, Model model) { | ||||||
|  |             ... | ||||||
|  |             List<Product> products = searchRepository.searchByName(search); | ||||||
|  |             model.addAttribute("products", products); | ||||||
|  |             ... | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     RegistrationController { | ||||||
|  |         @PostMapping("/registeruser") | ||||||
|  |         public String registerUser(@ModelAttribute("newuser") User user) { // <form method="post" modelAttribute="newuser" ...> | ||||||
|  |              | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     HomeController { | ||||||
|  |         ... | ||||||
|  |         @ModelAttribute("newuser") | ||||||
|  |         public User getDefaultUser() { return new User(); } | ||||||
|  |         @ModelAttribute("genderItems") | ||||||
|  |         public List<String> getGenderItems() { return List.of("Male", "Female", "Other"); } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     javax.validation -> hibernate validator | ||||||
|  |     annotate with @Valid our beans at controller and add BindingResult param right after the annotated one | ||||||
|  |     and add <form:errors path="someAttr".../> to our form elements | ||||||
|  |     in order to localize error messages, add resources/ValidationMessages.properties, add msg.key=msg.value | ||||||
|  |     and use ... message="{msg.key}" | ||||||
|  | 
 | ||||||
|  |     binders extend ModelAttribute-s | ||||||
|  |     User { | ||||||
|  |           | ||||||
|  |         private Date dateOfBirth; // <form:input path="dateOfBirth" type="date" .../> | ||||||
|  |     } | ||||||
|  |     RegistrationController { | ||||||
|  |         @InitBinder | ||||||
|  |         public void initBinder(WebDataBinder binder) { | ||||||
|  |             binder.registerCustomEditor(Date.class, "dateOfBirth", new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"))); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     converters extend binders concept, transform request data to desired types | ||||||
|  |     built in converters present, but we can provide custom ones | ||||||
|  | 
 | ||||||
|  |     public enum Gender { MALE, FEMALE, OTHER } | ||||||
|  |     User {  | ||||||
|  |         @Enumerated(EnumType.STRING) | ||||||
|  |         private Gender gender; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public class StringToEnumConverter implements .core.convert.Converter<String, Gender> { | ||||||
|  |         @Override | ||||||
|  |         public Gender convert(String s) { | ||||||
|  |             ... regurn Gender.GGG ...; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ApplicationConfig { | ||||||
|  |         ... | ||||||
|  |         @Override | ||||||
|  |         protected void addFormatters(FormatterRegistry registry) { | ||||||
|  |             registry.addConverter(new StringToEnumConverter()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     HandlerMapping - maps request to handler | ||||||
|  |     HandlerAdapter - invokes the handler | ||||||
|  |     ViewResolver - helps resolve views | ||||||
|  |     LocaleResolver - helps with l10n and i18n support | ||||||
|  |     ThemeResolver | ||||||
|  |     HandlerExceptionResolver - helps with exception handling | ||||||
|  |         ExceptionHandlerExceptionResolver - define ex-handling methods in controllers (annotated by @ExceptionHandler) | ||||||
|  |         SimpleMappingExceptionResolver - maps each ex-n class with an error page | ||||||
|  |         DefaultHandlerExceptionResolver - default, maps exceptions to error codes  | ||||||
|  |         ResponseStatusExceptionResolver - resolves custom exceptions using status code defined in @ResponseStatus (for ex-ns) | ||||||
|  |         to disable standard error resolver, we need to add property | ||||||
|  |         spring.autoconfigure.exclude=ord.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration | ||||||
|  | 
 | ||||||
|  |     public class Login { | ||||||
|  |         private String login; | ||||||
|  |         private String password; | ||||||
|  |     } | ||||||
|  |     HomeController { | ||||||
|  |         ... @ModelAttribute("login") public Login getDefaultLogin() { return new Login(); } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public class ApplicationException extends RuntimeException { ... } | ||||||
|  | 
 | ||||||
|  |     LoginController { | ||||||
|  |         @PostMapping("/login") | ||||||
|  |         public String login(@ModelAttribute("login") Login login) { | ||||||
|  |             User user = userRepository.searchByName(login.getUsername()); | ||||||
|  |             if (user == null) { | ||||||
|  |                 throw new ApplicationException("User not found"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         @ExceptionHandler(ApplicationException.class) | ||||||
|  |         public String handleException(ApplicationException ex, WebRequest request) { | ||||||
|  |             return "error"; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     for global handler | ||||||
|  |     @ControllerAdvice | ||||||
|  |     public class ApplicationExceptionHandler { | ||||||
|  |          | ||||||
|  |         @ExceptionHandler(ApplicationException.class) | ||||||
|  |         public String handleException(ApplicationException ex, WebRequest request) { | ||||||
|  |             return "error"; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     ... | ||||||
|  |     @ControllerAdvice | ||||||
|  |     public class DefaultModelAttributeController { | ||||||
|  |         @ModelAttribute("newuser") | ||||||
|  |         public User getDefaultUser() { return new User(); } | ||||||
|  |         @ModelAttribute("genderItems") | ||||||
|  |         public List<String> getGenderItems() { return List.of("Male", "Female", "Other"); } | ||||||
|  |         ... | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @EnableAsync | ||||||
|  |     https://stackoverflow.com/questions/36768234/spring-enableasync-breaks-bean-initialization-order | ||||||
|  |     https://www.baeldung.com/spring-async | ||||||
|  |     ...ApplicationAsync { | ||||||
|  |         @Override | ||||||
|  |         protected void configureAsyncSupport(AsyncSupportConfigurer configurer) | ||||||
|  |             configurer.setTaskExecutor(mvcTaskExecutor()); | ||||||
|  |             configurer.setDefaultTimeout(5000); | ||||||
|  |         } | ||||||
|  |         @Bean public AsyncTaskExecutor mvcTaskExecutor() { ThreadPoolTaskExecutor... } | ||||||
|  |     } | ||||||
|  |     ... SearchController { | ||||||
|  |         public Callable<String> search(..., HttpServletRequest request) { | ||||||
|  |             log.info(request.isAsyncSupported(), Thread.currentThread().getName()); | ||||||
|  |             return () -> { | ||||||
|  |                 log.info(Thread.currentThread().getName()); | ||||||
|  |                 all the business logic | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             we can also use DeferredResult | ||||||
|  |             @Autowired | ||||||
|  |             private AsyncTaskExecutor executor; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |             public DeferredResult<String> search(..., HttpServletRequest request) { | ||||||
|  |                 DeferredResult<String> defferedResult = new DeferredResult<>(); | ||||||
|  |                 ... | ||||||
|  |                 executor.execute(() -> { | ||||||
|  |                     ... | ||||||
|  |                     defferedResult.setResult(search); | ||||||
|  |                 }); | ||||||
|  |                 return defferedResult; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     View | ||||||
|  |     ViewResolver - resp by resolving views by names | ||||||
|  |         InternalResourceViewResolver | ||||||
|  |         ResourceBundleViewResolver | ||||||
|  |         XmlViewResolver | ||||||
|  |         VelocityViewResolver, FreeMakerViewResolver, ... | ||||||
|  |         ChainedViewResolver | ||||||
|  | 
 | ||||||
|  |     DispatcherServlet | ||||||
|  |         HandlerMapping, HandlerAdapter (calls interceptors) | ||||||
|  |             Pre-process Interceptors 1..n | ||||||
|  |             and then (iff all are OK) - calls a Controller | ||||||
|  |             after all business-logic - | ||||||
|  |             Post-process | ||||||
|  | 
 | ||||||
|  |     Impl-s of HandlerInterceptorAdapter base class | ||||||
|  |         preHandle | ||||||
|  |         postHandle | ||||||
|  |         afterCompletion - after response is completed to the client | ||||||
|  |     ThemeChangeInterceptor | ||||||
|  |     LocaleChangeInterceptor | ||||||
|  | 
 | ||||||
|  |     public class LoggingInterceptor extends HandlerInterceptorAdapter { | ||||||
|  |         @Override | ||||||
|  |         public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { | ||||||
|  |             ... | ||||||
|  |         } | ||||||
|  |         public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { | ||||||
|  |             ... | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     at ApplicationConfig { | ||||||
|  |         @Override | ||||||
|  |         protected void addInterceptors(InterceptorRegistry registry) { | ||||||
|  |             registry.addInterceptor(new LoggingInterceptor()).addPathPatterns("/*") | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ... @SessionAttributes, @SessionAttribute | ||||||
|  |         @RequestAttribute | ||||||
|  | 
 | ||||||
|  |     @Controller | ||||||
|  |     @SessionAttributes("login") // @ModelAttribute should exist | ||||||
|  |     public class LoginController { | ||||||
|  |          | ||||||
|  |         // already exposed by ControllerAdvice | ||||||
|  |         // @ModelAttribute("login") public Login getDefaultLogin() { return new Login(); } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Controller | ||||||
|  |     public class UserProfileController { | ||||||
|  |         @PostMapping("/userprofile") | ||||||
|  |         public String getUserProfile(@SessionAttribute("login") Login login, Model model) { | ||||||
|  |             // and similar for @RequestAttribute | ||||||
|  |             model.setAttribute("username"); // or use ${sessionScope.username} at jsp | ||||||
|  |             return "profile"; // use login in jsp | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LoginController { | ||||||
|  |         ... | ||||||
|  |         @PostMapping("/login") | ||||||
|  |         { | ||||||
|  |             session.setMaxInactiveTimeout(...) | ||||||
|  |             ... | ||||||
|  |             ... return "forward:/userprofile" | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Controller | ||||||
|  |     public class LogoutController { | ||||||
|  |         @GetMapping("/logout") | ||||||
|  |         public String logout(HttpSession session) { | ||||||
|  |             session.invalidate(); | ||||||
|  |             return "login"; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Controller | ||||||
|  |     public class RedirectionController { | ||||||
|  |         @GetMapping("/redirectToLinkedIn") | ||||||
|  |         public String redirectToLinkedIn() { | ||||||
|  |             return "redirect:http://www.linkedin.com"; // absolute URL is needed | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ThemeResolver facilitates theme resolution | ||||||
|  |         ThemeSource and default impl - ResourceBundleThemeSource | ||||||
|  |         CookieThemeResolver | ||||||
|  |         SessionThemeResolver | ||||||
|  |         FixedThemeResolver | ||||||
|  | 
 | ||||||
|  |     resources/client-theme1.properties | ||||||
|  |         styleSheet=/css/style1.css | ||||||
|  |     resources/client-theme2.properties | ||||||
|  |         styleSheet=/css/style2.css | ||||||
|  | 
 | ||||||
|  |     ... ApplicationConfig { | ||||||
|  |         @Bean | ||||||
|  |         public ThemeResolver themeResolver() { | ||||||
|  |             CookieThemeResolver cookieThemeResolver = new CookieThemeResolver(); | ||||||
|  |             cookieThemeResolver.setCookieName("theme"); | ||||||
|  |             cookieThemeResolver.setDefaultThemeName("client-theme1"); | ||||||
|  |             return cookieThemeResolver; | ||||||
|  |         } | ||||||
|  |         ... // also it's important to add an interceptor | ||||||
|  |         @Override | ||||||
|  |         protected void addInterceptors(InterceptorRegistry registry) { | ||||||
|  |             registry.addInterceptor(new LoggingInterceptor()).addPathPatterns("/*") | ||||||
|  |             registry.addInterceptor(new ThemeChangeInterceptor()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     // next thing - define at our jsp | ||||||
|  |     <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> | ||||||
|  |     ... | ||||||
|  |     <head> | ||||||
|  |         <link rel="stylesheet" href="<spring:theme code='styleSheet'/>" type="text/css"/> | ||||||
|  |         ... | ||||||
|  |     </head> | ||||||
|  |     // we can check with ...?theme=client-theme2... ... resolver will store this in cookie | ||||||
|  | 
 | ||||||
|  |     l10n - is to use props for msgs | ||||||
|  |     i10n - is more than l10n, including locale treatment | ||||||
|  | 
 | ||||||
|  |     LocaleResolver | ||||||
|  |         AcceptHeaderLocaleResolver - default one | ||||||
|  |         CookieLocaleResolver | ||||||
|  |         SessionLocaleResolver | ||||||
|  | 
 | ||||||
|  |     resources/messages.properties | ||||||
|  |         label.home=home | ||||||
|  |         label.search=search | ||||||
|  |         label.login=login | ||||||
|  |         label.linkedin=linkedin | ||||||
|  |     resources/messages_sv.properties // make sure to have UTF-8 | ||||||
|  |         label.home=hem | ||||||
|  |         label.search=sok | ||||||
|  |         label.login=logga in | ||||||
|  |         label.linkedin=... | ||||||
|  | 
 | ||||||
|  |     // at jsp - use <spring:message code="label.home"/> | ||||||
|  |     // default resolver takes locale from client settings of browser | ||||||
|  | 
 | ||||||
|  |     ... ApplicationConfig { | ||||||
|  |         @Bean | ||||||
|  |         public LocaleResolver localeResolver() { | ||||||
|  |             CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver(); | ||||||
|  |             cookieLocaleResolver.setCookieName("locale"); | ||||||
|  |             cookieLocaleResolver.setDefaultLocale(Locale.US); | ||||||
|  |             return cookieLocaleResolver; | ||||||
|  |         } | ||||||
|  |         ... // also it's important to add an interceptor | ||||||
|  |         @Override | ||||||
|  |         protected void addInterceptors(InterceptorRegistry registry) { | ||||||
|  |             registry.addInterceptor(new LoggingInterceptor()).addPathPatterns("/*") | ||||||
|  |             registry.addInterceptor(new ThemeChangeInterceptor()); | ||||||
|  |             registry.addInterceptor(new LocaleChangeInterceptor()); // can customize with setParamName if need non-default | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     REST: spring uses HttpMessageConvertors for JSON (with Jackson), no view name needed | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     @Controller | ||||||
|  |     public class ProductsRestController { | ||||||
|  |         ... | ||||||
|  |         @GetMapping("/rest/products")  | ||||||
|  |         @ResponseBody | ||||||
|  |         public List<Product> getProducts() { | ||||||
|  |             return productRepository.findAll(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     @RestController // implies @ResponseBody for every method | ||||||
|  |     public class ProductsRestController { | ||||||
|  |         ... | ||||||
|  |         @GetMapping("/rest/products")  | ||||||
|  |         public ResponseEntity<List<Product>> getProductsByParam(@RequestParam("name") String name) { | ||||||
|  |             List<Product> products = productRepository.searchByName(name) | ||||||
|  |             return new ResponseEntity<>(products, HttpStatus.OK); | ||||||
|  |         } | ||||||
|  |         @GetMapping("/rest/products/{id}")  | ||||||
|  |         public ResponseEntity<List<Product>> getProductsByPathVar(@PathVariable("name") String name) { | ||||||
|  |             List<Product> products = productRepository.searchByName(name) | ||||||
|  |             return new ResponseEntity<>(products, HttpStatus.OK); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public class LoginFailureException extends Exception { | ||||||
|  |         ... | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @RestController | ||||||
|  |     public class LoginRestController { | ||||||
|  |         ... | ||||||
|  | 
 | ||||||
|  |         @PostMapping("/rest/loginuser")  | ||||||
|  |         public ResponseEntity<?> loginUser(@RequestBody Login login) { | ||||||
|  |             User user = userRepository.searchByName(login.getUsername()); | ||||||
|  |             if (user == null) { | ||||||
|  |                 return new ResponseEntity.status(HttpStatus.NOT_FOUND).build(); | ||||||
|  |             } | ||||||
|  |             if (user.getUsername().equals(login.getUsername)) && ... pwd) { | ||||||
|  |                 return new ResponseEntity<>("Welcome " + user.getUsername(), HttpStatus.OK); | ||||||
|  |             } else { | ||||||
|  |                 throw new LoginFailureException("username or password is incorrect") | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @ExceptionHandler(LoginFailureException.class) | ||||||
|  |         public ResponseEntity<?> handle Login(LoginFailureException ex) { | ||||||
|  |             return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ex.getMessage()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| @ -6,3 +6,53 @@ Udemy - Learn integration testing with Spring Boot | |||||||
| Advanced Spring - Effective Integration Testing with Spring Boot | Advanced Spring - Effective Integration Testing with Spring Boot | ||||||
|     magnet:?xt=urn:btih:afd24823c218c0cc876504cb86723cfc44b9ab29 |     magnet:?xt=urn:btih:afd24823c218c0cc876504cb86723cfc44b9ab29 | ||||||
|     ! 201.5m, non-complete |     ! 201.5m, non-complete | ||||||
|  | 
 | ||||||
|  | https://www.linkedin.com/learning/spring-boot-test-driven-development | ||||||
|  |     AopTestUtils | ||||||
|  |     ReflectionTestUtils | ||||||
|  |     MvcTestUtils, Mvc test client, MockMvc | ||||||
|  | 
 | ||||||
|  |     Unit Test | ||||||
|  |     @ExtendsWith(MockitoExtension.class) | ||||||
|  |     Integration | ||||||
|  |     @SpringBootTest(classes=MyConfig.class) | ||||||
|  |     @AutoConfigureTestDatabase(replace=Replace.ANY) | ||||||
|  |     @AutoConfigureMockMvc | ||||||
|  |         @Autowired | ||||||
|  |         MockMvc mockMvc; | ||||||
|  |         someTestMethod() { | ||||||
|  |             mockMvc.perform(get("/someEndpoint")) | ||||||
|  |               .andExpect(status().isOk()) | ||||||
|  |               .andExpect(content().string(containsString("some-uuid"))) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | https://www.linkedin.com/learning/advanced-spring-effective-integration-testing-with-spring-boot | ||||||
|  |     @SpringBootTest | ||||||
|  |     @DataJpaTest (without web layer), @DataJdbcTest, ... @DataRedisTest | ||||||
|  |     @WebMvcTest (loads web-layer only to the context without persistence layer), @RestClientTest, @WebServiceClientTest, @WebFluxTest | ||||||
|  |     @MockBean ? for UT | ||||||
|  |     BDDMockito lib | ||||||
|  |         instead of when(methodCall).then(doSomething) | ||||||
|  |         given(methodCall).will(doSomething) | ||||||
|  | 
 | ||||||
|  |     TestEntityManager mgr | ||||||
|  |     mgr.persistFlushFind(obj) -> to bypass hbm L1 cache | ||||||
|  | 
 | ||||||
|  |     @ExtendsWith(MockitoExtension.class) | ||||||
|  |     @InjectMock - uses constructor or setter injection | ||||||
|  |     @Mock - replaces whole class entirely | ||||||
|  |     @Spy - takes existing object and replaces only some methods | ||||||
|  |     @MockBean and @SpyBean | ||||||
|  | 
 | ||||||
|  |     @ExceptionHandler+@ResponseStatus() | ||||||
|  |     or @ResponseStatus(HttpStatus.NOT_FOUND) | ||||||
|  |     public void someMethod(SomeEx-n) | ||||||
|  |     mockito given().willThrow(...) | ||||||
|  | 
 | ||||||
|  |     @RestClientTest (MockRestServiceServer, only for RestTemplate) | ||||||
|  |     WireMock is better | ||||||
|  | 
 | ||||||
|  |     SpringCloudContract (generate tests by contract def-n),  | ||||||
|  |         StubRunner fetches generated jar and spins stub-server at config-d port | ||||||
|  |         @SpringBootTest | ||||||
|  |         @AutoConfigureStubRunner(ids="group:artifact:+:8080", stubsMode=StubRunnerProperties.StubsMode.LOCAL) | ||||||
|  | |||||||
| @ -0,0 +1,6 @@ | |||||||
|  | https://github.com/tkaczmarzyk/specification-arg-resolver | ||||||
|  | https://github.com/tkaczmarzyk/specification-arg-resolver/tree/master/src/main/java/net/kaczmarzyk/spring/data/jpa/web/annotation | ||||||
|  | https://github.com/tkaczmarzyk/specification-arg-resolver/tree/master/src/main/java/net/kaczmarzyk/spring/data/jpa/domain | ||||||
|  | 
 | ||||||
|  | 2017 | ||||||
|  | https://blog.tratif.com/2017/11/23/effective-restful-search-api-in-spring/ | ||||||
		Загрузка…
	
	
			
			x
			
			
		
	
		Ссылка в новой задаче
	
	Block a user
	 Ihar Hancharenka
						Ihar Hancharenka