- JUnit testing, use of Mockito
Bale
- After creating the directory with war, the IDE will help to generate the required directory for the web application
- webapp directory
- Also add something to pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>springboot</groupId> <artifactId>chapter15</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>chapter15</name> <description>chapter15 project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.0.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
- mvn package
- java -jar spring-0.0.1-snapshot.war
- java -jar spring-0.0.1-snapshot.war --server.port=9080
-
To use a third-party non-embedded server, you need to initialize the Dispatcher yourself
public class ServletInitializer extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(Chapter15Application.class); } }
- mvc provides the implementation class of ServletContainerinitializer: SpringServletContainerInitializer
- This class: It will traverse the implementation class of the WebApplicationInitializer interface.
- Among them: SprigBootServletInitializer is its implementation class
-
Just copy xxx.war to the webapps directory of tomcat.
hot deployment
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>
- true dependencies will not be passed, other projects depend on the current project, and this hot deployment will not take effect on this project.
- Hot deployment is passed, and LiveReload supports it.
- Hot deployment There are many configurations, see for yourself
test
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
- Support Jpa, MongoDB, Rest, Redis
- Mock test
@RunWith(SpringRunner.class) //The loaded class is the operation of Spring combined with JUnit //Start the test service with a random port. Configure Test Related Features @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) public class Chapter16ApplicationTests { // Inject the user service class @Autowired private UserService userService = null; @Test public void contextLoads() { User user = userService.getUser(1L); // Determine if user information is empty Assert.assertNotNull(user); } // REST test template, provided automatically by Spring Boot @Autowired private TestRestTemplate restTemplate = null; // Test get user function @Test public void testGetUser() { // Request the currently started service, note the URI abbreviation User user = this.restTemplate.getForObject("/user/{id}", User.class, 1L); Assert.assertNotNull(user); } @MockBean private ProductService productService = null; @Test public void testGetProduct() { // Build dummy objects Product mockProduct = new Product(); mockProduct.setId(1L); mockProduct.setProductName("product_name_" + 1); mockProduct.setNote("note_" + 1); // Specify Mock Bean methods and parameters BDDMockito.given(this.productService.getProduct(1L)) // Specifies the returned virtual object .willReturn(mockProduct); // Mock test Product product = productService.getProduct(1L); Assert.assertTrue(product.getId() == 1L); } } public Product getProduct(Long id) { throw new RuntimeException("Failed to support this method"); }
mock test
- During testing, use a dummy object to create a test method for testing
- getProduct(1L) currently cannot schedule product microservices, mock can give a virtual product
- @MockBean Mock test for that bean
actuator monitoring endpoint
<dependency> <groupId>org.springframework.hateoas</groupId> <artifactId>spring-hateoas</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
- hateoas is a complex constraint in the REST architectural style, a dependency for building mature REST services.
actuator endpoint description
- health
- httptrace latest trace information (100 by default)
- info
- mappings all mapping paths
- scheduledtasks shows scheduled tasks
- shutdown
http monitoring
- http://localhost:8080/actuator/health
- http://localhost:8080/actuator/beans needs to be enabled
- Default values expose info and health
# Expose all endpoints info,health,beans management.endpoints.web.exposure.include=* #Do not expose this endpoint management.endpoints.web.exposure.exclude=env # By default all endpoints are not enabled, in this case you need to enable endpoints on demand management.endpoints.enabled-by-default=false # enable endpoint info management.endpoint.info.enabled=true # Enable endpoint beans management.endpoint.beans.enabled=true management.endpoint.health.enabled=true management.endpoint.dbcheck.enabled=true # Actuator endpoint prefix management.endpoints.web.base-path=/manage management.endpoint.health.show-details=when-authorized management.health.db.enabled=true
View sensitive information
- The above is fully exposed, very incomplete
@SpringBootApplication(scanBasePackages = "com.springboot.chapter16") @MapperScan(basePackages = "com.springboot.chapter16", annotationClass = Mapper.class) public class Chapter16Application extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // password encoder PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); // use memory storage auth.inMemoryAuthentication() // Set password encoder .passwordEncoder(passwordEncoder) // Register the user admin, the password is abc, and give the role permissions of USER and ADMIN .withUser("admin") // The encrypted password can be obtained by passwordEncoder.encode("abc") .password("$2a$10$5OpFvQlTIbM9Bx2pfbKVzurdQXL9zndm1SrAjEkPyIuCcZ7CqR6je").roles("USER", "ADMIN") // connection method and .and() // Register the user myuser, the password is 123456, and give the role permission of USER .withUser("myuser") // The encrypted password can be obtained by passwordEncoder.encode("123456") .password("$2a$10$ezW1uns4ZV63FgCLiFHJqOI6oR6jaaPYn33jNrxnkHZ.ayAFmfzLS").roles("USER"); } @Override protected void configure(HttpSecurity http) throws Exception { // Endpoints that need Spring Security protection String[] endPoints = {"auditevents", "beans", "conditions", "configprops", "env", "flyway", "httptrace", "loggers", "liquibase", "metrics", "mappings", "scheduledtasks", "sessions", "shutdown", "threaddump"}; // Define the endpoints that need to be authenticated // http.requestMatcher(EndpointRequest.to(endPoints)) http.authorizeRequests().antMatchers("/manage/**").hasRole("ADMIN") // Request to close page requires ROLE_ADMIN orange .antMatchers("/close").hasRole("ADMIN") .and().formLogin() .and() // Start HTTP Basic Authentication .httpBasic(); } public static void main(String[] args) { SpringApplication.run(Chapter16Application.class, args); } }
http. requestMatcher(EndpointRequest.to(endPoints)).authorizeRequests().anyRequest().hasRole("ADMIN"). and() .antMatchers("/close").authorizeRequests().anyRequest().hasRole("ADMIN"); .authorizeRequests().anyRequest() //After signing in
shutdown endpoint
management.endpoint.shutdown.enabled=true
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <!-- load Query document--> <script src="https://code.jquery.com/jquery-3.2.0.js"></script> <script type="text/javascript"> $(document).ready(function () { $("#submit").click(function () { // request shutdown endpoint $.post({ url: "./actuator/shutdown", // method after success success: function (result) { // Check request result if (result != null || result.message != null) { // print message alert(result.message); return; } alert("closure Spring Boot Application failed"); } }); }); }); </script> <title>test close request</title> </head> <body> <input id="submit" type="button" value="close the app"/> </body> </html> @RestController public class CloseController { @GetMapping("/close") public ModelAndView close(ModelAndView mv) { // Define the view name as close and let it jump to the corresponding JSP mv.setViewName("close"); return mv; } }
Configure endpoints
management.server.port=8080 # expose all endpoints management.endpoints.web.exposure.include=* # management.endpoints is public # By default all endpoints are not enabled, in this case you need to enable endpoints on demand .enabled-by-default=false # enable endpoint info .info.enabled=true # Enable endpoint beans .beans.enabled=true # enable config endpoint .configprops.enabled=true # start env .env.enabled=true # enable health .health.enabled=true # enable mappings .mappings.enabled=true # enable shutdown .shutdown.enabled=true # Actuator endpoint prefix .web.base-path=/manage # Modify the request path of the original mapping endpoint to urlMapping .web.path-mapping.mappings=request_mappings
-
http://localhost:8000/manage/health
{ "status":"UP", "details":{ "www":{ "status":"UP", "details":{ "message":"The current server has access to the World Wide Web." } }, "diskSpace":{ "status":"UP", "details":{ "total":302643146752, "free":201992957952, "threshold":10485760 } }, "db":{ "status":"UP", "details":{ "database":"MySQL", "hello":1 } } } }
custom endpoint
// Let Spring scan the class @Component // define endpoints @Endpoint( // endpoint id id = "dbcheck", // Whether the endpoint is enabled by default enableByDefault = true) public class DataBaseConnectionEndpoint { private static final String DRIVER = "com.mysql.jdbc.Driver"; @Value("${spring.datasource.url}") private String url = null; @Value("${spring.datasource.username}") private String username = null; @Value("${spring.datasource.password}") private String password = null; // An endpoint can only have one method annotated with @ReadOperation // It represents an HTTP GET request @ReadOperation public Map<String, Object> test() { Connection conn = null; Map<String, Object> msgMap = new HashMap<>(); try { Class.forName(DRIVER); conn = DriverManager.getConnection(url, username, password); msgMap.put("success", true); msgMap.put("message", "Test database connection is successful"); } catch (Exception ex) { msgMap.put("success", false); msgMap.put("message", ex.getMessage()); } finally { if (conn != null) { try { conn.close(); // close database connection } catch (SQLException e) { e.printStackTrace(); } } } return msgMap; } }
management.endpoint.dbcheck.enabled=true
{"success":true,"message":"Test database connection is successful"}
Custom World Wide Web Health Metrics
http://localhost:8080/manage/health has been accessed above // The monitoring server is capable of accessing the World Wide Web @Component public class WwwHealthIndicator extends AbstractHealthIndicator { // By monitoring Baidu server, see if you can access the Internet private final static String BAIDU_HOST = "www.baidu.com"; // overtime time private final static int TIME_OUT = 3000; @Override protected void doHealthCheck(Builder builder) throws Exception { boolean status = ping(); if (status) { // The health indicator is available and a message item is added builder.withDetail("message", "The current server has access to the World Wide Web.").up(); } else { // The health indicator is no longer in service, and a message item is added builder.withDetail("message", "The World Wide Web is currently unavailable").outOfService(); } } // Monitoring Baidu server access to determine whether access to the World Wide Web private boolean ping() throws Exception { try { // When the return value is true, the host is available, and false is not. return InetAddress.getByName(BAIDU_HOST).isReachable(TIME_OUT); } catch (Exception ex) { return false; } } }
JMX monitoring
jconsole.exe
Select: org.springframework.boot—endpoint—health—click health