Exception Processing @RestControllerAdvice in Spring

A very useful class in the Spring 4 plus is the  @RestControllerAdvice, it combines the @ControllerAdvice inside. By defining a @RestControllerAdvice, when a controller thorw one exception, you can put all the exception handlers code into one class and you then can choose to use different @ExceptionHandler method to deal with different exceptions , or you even can deal all in one method to use the instance check up to decide what response msg you should send out in response;

So you have chance to reply user a friend msg of your runtime exception of your Restful API, and even with customized http status code too with ResponseEntity class.

Here I put a fake sample code to show how it works. you can do more study and use the handler in your way. Result is a class you defined Object your want to reply to client side.


@RestControllerAdvice
public class GlobalExceptionHandler {

private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);

@ExceptionHandler(value = { MyCustomizedException.class })
 @ResponseStatus(HttpStatus.BAD_REQUEST)
public Result myCustomizedExceptionHandler(MyCustomizedException ex) {
 // ..... what ever process
 return new Result(500, 0001, ex.getMessage());
 }


@SuppressWarnings("rawtypes")
 @ExceptionHandler(value = Exception.class)
 public ResponseEntity handle(Exception e) {
 e.printStackTrace();
 Result rt = new Result(e.getMessage());

if (e instanceof SoaException) {
 rt = ((SoaException) e).getBodyStatus();
 } else if (e instanceof MissingServletRequestParameterException) {
 rt = DataUtil.rt("0002");
 } else if (e instanceof HttpRequestMethodNotSupportedException) {
 rt = DataUtil.rt("0003");
 } else if (e instanceof HttpMediaTypeNotSupportedException) {
 rt = DataUtil.rt("0004");
 } else if (e instanceof HttpMessageNotReadableException) {
 rt = DataUtil.rt("0005");
 } else if (e instanceof BindException) {
 rt = DataUtil.rt("0006");
 } else if (e instanceof NumberFormatException) {
 rt = DataUtil.rt("0007");
 } else if (e instanceof DataIntegrityViolationException) {
 rt = DataUtil.rt("0008");
 } else {
 rt = DataUtil.rt(Constants.ERROR_CODE);
 }
 LOGGER.error(rt.getMessage() + e);
 return new ResponseEntity<>(rt, HttpStatus.OK);
 }

 

Advertisements

Spring Admin Server and UI for Spring Boot Application – 2

Now , let us add the security login for the spring admin server.

1. Add these into pom.xml

<dependency>
 <groupId>de.codecentric</groupId>
 <artifactId>spring-boot-admin-server-ui-login</artifactId>
 <version>1.5.7</version>
 </dependency>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-security</artifactId>
 </dependency>

spring-boot-admin-server-ui-login will supply the login and logout page.

 

2. Create a web security config class like this:

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Override
 protected void configure(HttpSecurity http) throws Exception {
 http.formLogin().loginPage("/login.html").loginProcessingUrl("/login").permitAll();
 http.logout().logoutUrl("/logout");
 http.csrf().disable();
 http.authorizeRequests().antMatchers("/login.html", "/**/*.css", "/img/**", "/third-party/**").permitAll();
 http.authorizeRequests().antMatchers("/**").authenticated();
 http.httpBasic();
 }
}

 

3. put this into the application.properties

management.security.enabled=true
security.user.name=admin
security.user.password=*******

Restart and now you need login to access the server UI.

Screenshot from 2018-04-27 15-37-57

 

But now, you will lost your client app in the UI. To let the client can access the server URL to exchange the data to server, we also need to change client configuration:

Just add this into client application.properties, the server can connect with client again:

management.security.enabled = false
spring.boot.admin.username=admin
spring.boot.admin.password=*******

management.security.enabled = false is to tell the server no need the security policy to access the client URL of actuator.   But client will use admin account to login to the server side to submit data…

 

Here I have done the demo for the single client and server admin UI login.  Next step you need to look at in the discovery  and eureka environment, how to link one server with more clients in cluster.

Please refer the doc of admin server for more details.

https://codecentric.github.io/spring-boot-admin/1.5.7/

 

Spring Admin Server and UI for Spring Boot Application – 1

The one of best parts of the Spring boot  is it have some great tools can add on to your application to have basic feature of a production system. Beside last time swagger for Spring boot, this time we add the Spring Admin Server to the application.

To monitoring your system health, you need to create a admin server ruuning as a standalone application, eg at port 8081 this time. So from this server , we can admin all the spring boot applications’ health.

We will first create a new app to run the admin server first.

1. Create a new Spring boot app with “web” enabled.

2. Add this to pom.xml

<dependency>
 <groupId>de.codecentric</groupId>
 <artifactId>spring-boot-admin-starter-server</artifactId>
 <version>1.5.7</version>
 </dependency>

3. Add this to the application.properties

spring.application.name=ServersMonitor
server.port=8081

 

4. Just add the @EnableAdminServer to the application main class:

@EnableAdminServer
@SpringBootApplication
public class MonitorApplication {

public static void main(String[] args) {
 SpringApplication.run(MonitorApplication.class, args);
 }
}

Ok , sever is ready, start it and surf to http://localhost:8081  you will see the Admin UI but with no application be monitored there.

 

Now let change one app as the client that will be monitored by admin.

1. Add the dependency in pom.xml, bold text part!

<!-- Spring admin UI client ===================================================== -->
 <!-- Spring admin UI client ===================================================== -->
 <dependency>
 <groupId>de.codecentric</groupId>
 <artifactId>spring-boot-admin-starter-client</artifactId>
 <version>1.5.7</version>
 </dependency>
 </dependencies>
 <build>
 <plugins>
 <plugin>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-maven-plugin</artifactId>
 <executions>
 <execution>
 <goals>
 <goal>build-info</goal>
 </goals>
 </execution>
 </executions>
 </plugin>
 </plugins>
 </build>
</project>

2. Add this to the application.properties, as our admin server running at 8081

# =======================================================================================
# For Spring Admin UI client side
# =======================================================================================
spring.boot.admin.url = http://localhost:8081 
management.security.enabled: false

3. All done, just start our app, it is running at 8082 port.  then go back to admin server UI, we will see it auto has one application be monitored!

Screenshot from 2018-04-27 14-37-35

 

And we can check all health info about our client applications from here:

Screenshot from 2018-04-27 14-37-43.png

Bingo. have a rest and we will proceed to the security login part!

 

Thanks for this link about some process and basics.

http://www.baeldung.com/spring-boot-admin

 

Swagger for Spring Boot How To

This is the note about how to make the swagger work together with Spring Boot. Swagger here is used as great tool to automatically create the Restful API html docs and testing API web UI.

1. Add swagger2 and UI to POM.XML

<dependency>
 <groupId>io.springfox</groupId>
 <artifactId>springfox-swagger2</artifactId>
 <version>2.6.1</version>
 <scope>compile</scope>
 </dependency>

<dependency>
 <groupId>io.springfox</groupId>
 <artifactId>springfox-swagger-ui</artifactId>
 <version>2.6.1</version>
 <scope>compile</scope>
 </dependency>

2. Create a class for spring boot configuration for swagger:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import static springfox.documentation.builders.PathSelectors.regex;

@EnableSwagger2
@Configuration
public class SwaggerConfig {

@Bean
 public Docket productApi() {
 return new Docket(DocumentationType.SWAGGER_2).select()
 .apis(RequestHandlerSelectors.basePackage("com.wayneshare.springboot.swaggerexample"))
 .paths(regex("/rest.*")).build().apiInfo(metaInfo());
 }

private ApiInfo metaInfo() {

ApiInfo apiInfo = new ApiInfo("WayneShare RestfulAPI", "Enable knowledge sharing ...", "1.0",
 "Terms of Service", new Contact("WayneShare", "https://www.wayneshare.com", "zhou_xiaowei@yahoo.com"),
 "", "");

return apiInfo;
 }
}

3. Then you can start run the application and goes to this URL http://localhost:8080/swagger-ui.html

You will see the swagger API html docs and can test over there.

4.  Try to change this part of code in config to see changes on the UI, then you will know the meta data reflecting on UI.

ApiInfo apiInfo = new ApiInfo("WayneShare RestfulAPI", "Enable knowledge sharing ...", "1.0",
 "Terms of Service", new Contact("WayneShare", "https://www.wayneshare.com", "zhou_xiaowei@yahoo.com"),
 "", "");

5. If you want to change the grouping name and description for one controller, then use @Api for you controller:

@RestController
@RequestMapping("/rest/account")
@Api(tags = "API 02", description = "Account info management")
public class AccountController {

6. Check these annotations too in case you want to change some meta on UI  and even the http return code desc. @ApiModelProperty @ApiOperation @ApiResponses

@ApiOperation(value = "Returns Authentication Result")
 @ApiResponses(value = { @ApiResponse(code = 200, message = "Successful Authentication") })

7. You can also run the testing for each API. Here is the final result I have done for a sample project:

Screenshot from 2018-04-27 10-41-10

Enjoy it and credit goes two these two links

https://github.com/TechPrimers/spring-boot-swagger-example

https://github.com/indrabasak/swagger-deepdive/wiki/Renaming-and-Sorting-REST-Controllers

How to do the mount and check the NFS server shared from Linux client

Here is some major commands to mount to NFS server from a client:

sudo apt-get install cifs-utils

sudo mkdir /media/temp

change your /etc/fstab file to let it mount on boot up

//nfsserver/temp /media/temp cifs guest,uid=1000,iocharset=utf8 0 0

then can use

mount -a

to do a manually mount

And here is how to check waht folder avaliable from a server to be mounted? and what address they permitted?

sudo apt install nfs-common
showmount -e 10.1.1.22

Export list for 10.1.1.22:
/volume1/shared 10.1.1.0/24
/volume1/SW 10.1.1.156
/volume1/backup 10.1.1.0/24

 

Build NAT for Vmware Esxi with pfSense

By default, Vmware Esxi hyper-visor doe not support NAT, it only gives bridge to the guest VMs to get the network address. So when you do not have enough DHCP resources to assign to many VMs in your network, NAT will be a option to let the VMs can share IP resources and also let outside can access VMs.

Here is some links I refereed when I did our Esxi + pfSense servers reconfiguration recently.

https://doc.pfsense.org/index.php/PfSense_on_VMware_vSphere_/_ESXi

http://blog.romant.net/technology/configuring-nat-on-esx-and-esxi/

https://sxkdz.org/vmware-esxi-and-pfsense-router-deploy/

https://www.jsnowcreations.com/guides/computer-guides/setup-steps-for-single-nic-hetzner-root-server-running-esxi-with-pfsense-router/

And I note down some points you need to pay attention when doing this , my cases are in the 5.1 and 5,5 version Esxi:

1. If you only have one physical NIC running (vmnic0), then you need one IP for VMware Management Interface,  and another IP for pfSense WAN interface, these two IP running at same NIC interface. So two IPs face to outside is minimum for NAT even in one NIC case.

2. vSwitch0 is used by VMs by default, and your new created switch group (not binding to any NIC) will be vSwitch1. So normally pfSense will have two virtual network interface: WAN binding to the vSwitch0 and LAN binding to the vSwitch1 to work as the NAT gateway.

3. After you have the pfSense running, assign some VMs to the LAN and you then can surf from LAN VM to the pfSense LAN interface (LAN gateway)’s http admin UI to manage the pfSense,  with default account admin/pfsense. You need to have basic firewall and LAN gateway knowledge to manage this gateway.

4. To let outside client to access the VM, you need to config the NAT port forwarding at the pfSense WAN interface. And also pay attention to the default check box of the firewall policy to let the 10.****, 198.*****, 172**** can access the your VM if you need it.

4. For the flexibility of the system pfSense WAN MAC can be changed, but not LAN side. you may need a reboot of the pfSense when you change the WAN MAC.

Spring boot actuator – system monitoring and management

I am using the 1.5.10 as the example, detailed docs can see at here:

https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/html/production-ready.html

1. Just add starter-actuator to maven

<!– for logging and minitoring =============================== –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2. Restart and suppose my app running at the 8080 port, you can see the actuator works at http://localhost:8080/health

{
  "status" : "UP",
  "diskSpace" : {
    "status" : "UP",
    "total" : 217631211520,
    "free" : 20183724032,
    "threshold" : 10485760
  },
  "rabbit" : {
    "status" : "UP",
    "version" : "3.5.7"
  },
  "db" : {
    "status" : "UP",
    "database" : "MySQL",
    "hello" : 1
  }
}

actuator gives you a lot data about your system, such as metrics, health, configuration, http trace ….FULL list can see from here ID List

3. Some ID will be blocked by spring security if your system using it. So you have to authenticate and get the token or get the role to access them. But if system is behind a firewall, you can disable the security for actuator. Let us change the actuator to running in a different port and using new path root to access it. Add these into the application.properties file:

management.port = 9091
management.address = 127.0.0.1
management.security.enabled=false
management.context-path=/manage
endpoints.jmx.enabled=false

So we can access http://localhost:9091/manage/health  now to get data.

4. Based on actuator feature, you can monitor and manage the system performance and health,  logging, and many others.  And use actuator API to process data by your self.

5. There are some GUI feature has been done based on the actuator already. like this one:

spring-boot-admin

Try to use it for your system!