Use of spring-boot-starter-jersey

jersey, like resteasy, is the implementation of JAX-RS, the Java API for RESTful Web Services standard. spring-boot-starter-jersey provides support for the Jersey RESTful Web service framework, allowing us to easily build RESTful Web projects.

New Construction

<groupId>com.wl.jersey</groupId>
<artifactId>jersey</artifactId>
<version>1.0-SNAPSHOT</version>

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>com.wl.jersey</groupId>
  <artifactId>jersey</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>jersey</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <MainClass>com.wl.jersey.Application</MainClass>

    <spring-boot-version>1.5.7.RELEASE</spring-boot-version>
    <commons-io-version>2.6</commons-io-version>
    <slf4j-api-version>1.7.5</slf4j-api-version>

  </properties>

  <dependencies>


    <!-- spring boot -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>${spring-boot-version}</version>
      <exclusions>
        <exclusion>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-api</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jersey -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jersey</artifactId>
      <version>1.5.7.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.glassfish.jersey.media</groupId>
      <artifactId>jersey-media-multipart</artifactId>
      <version>2.25.1</version>
    </dependency>

    <!---日志 -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>${slf4j-api-version}</version>
    </dependency>

    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>${commons-io-version}</version>
    </dependency>
    


    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <version>${spring-boot-version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
      <version>${spring-boot-version}</version>
    </dependency>
  </dependencies>

  <!-- Package as an executable jar -->
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>${spring-boot-version}</version>
        <configuration>
          <mainClass>${MainClass}</mainClass>
          <layout>JAR</layout>
        </configuration>
        <!-- repackage  生成两个 jar.original -->
        <executions>
          <execution>
            <goals>
              <goal>repackage</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <!-- 指定maven 打包java 版本 -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
    <!-- maven  编译打包resource 和 java 目录下所有文件  maven默认资源路径是resources -->
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <includes>
          <include>**/*.*</include>
          <include>*.*</include>
        </includes>
      </resource>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.*</include>
          <include>*.*</include>
        </includes>
      </resource>
    </resources>
  </build>
</project>

application.properties

server.port=10001

Start class

package com.wl.jersey;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;

/**
 * Created by Administrator on 2019/3/21.
 */
@SpringBootApplication(exclude = {
        DataSourceAutoConfiguration.class,
        DataSourceTransactionManagerAutoConfiguration.class,
        HibernateJpaAutoConfiguration.class             //不使用数据库
},scanBasePackages = "com.wl")
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Application.class);
        app.setWebEnvironment(true);
        app.run(args);
        logger.info("application init success");
    }

}

Configuration class

package com.wl.jersey.config;

import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.annotation.Configuration;

import javax.ws.rs.ApplicationPath;

/**
 * Created by Administrator on 2019/3/23.
 */
@Configuration
@ApplicationPath("/app")
public class JerseyConfig extends ResourceConfig {

    public JerseyConfig(){
        packages("com.wl");
        //防止文件上传报错No injection source found for a parameter of type public
        register(MultiPartFeature.class);
//        register(HelloWorldResource.class);
    }


}

ResourceConfig is The resource configuration for configuring a web application

packages("com.wl") is the Adds array of package names which will be used to scan for components, that is, all JAX-RS components under the specified package name will be scanned

register(HelloWorldResource.class) is to register HelloWorldResource as a custom JAX-RS component (Register a class of a custom JAX-RS component)

HelloWorldResource

package com.wl.jersey.resource;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

/**
 * Created by Administrator on 2019/3/23.
 */
@Consumes(MediaType.WILDCARD)
@Produces({MediaType.APPLICATION_JSON,MediaType.TEXT_PLAIN})
@Path("/hello")
public class HelloWorldResource {

    @Path("/world")
    @GET
    public String helloWorld(){
        return "hello world";
    }


}

The @Consumes annotation indicates the MIME  type of the request that can be accepted (Content-Type of the request header), which can be applied to the method

@MediaType is an enumeration corresponding to Content-Type WILDCARD means all types

The @Produces annotation indicates the MIME type of the response (Content-Type of the response header)

@Path annotation indicates the request path

The @GET annotation indicates the request method. Common ones are get post

Start the application and visit http://localhost:10001/hello/world

JAX-RS is simple to use

1. Set the service base URI, there are three ways to set the service base URI

       1.1 Use @ApplicationPath annotation. Modify JerseyConfig as follows (adding this annotation to the javax.ws.rs.core.Application subclass is invalid)

           

package com.wl.jersey.config;

import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.annotation.Configuration;

import javax.ws.rs.ApplicationPath;

/**
 * Created by Administrator on 2019/3/23.
 */
@Configuration
@ApplicationPath("/app")
public class JerseyConfig extends ResourceConfig {

    public JerseyConfig(){
        packages("com.wl");
//        register(HelloWorldResource.class);
    }
}

       1.2 Use the application.properties configuration file to add spring.jersey.application-path=/app configuration as follows

        

server.port=10001
spring.jersey.application-path=/app

      1.3 Use ServletRegistrationBean to modify the startup class as follows

package com.wl.jersey;

import com.wl.jersey.config.JerseyConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.servlet.ServletProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;

/**
 * Created by Administrator on 2019/3/21.
 */
@SpringBootApplication(exclude = {
        DataSourceAutoConfiguration.class,
        DataSourceTransactionManagerAutoConfiguration.class,
        HibernateJpaAutoConfiguration.class             //不使用数据库
},scanBasePackages = "com.wl")
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Application.class);
        app.setWebEnvironment(true);
        app.run(args);
        logger.info("application init success");
    }

    @Bean
    public ServletRegistrationBean jerseyServlet() {
        ServletRegistrationBean registration = new ServletRegistrationBean(
                new ServletContainer(), "/app/*");
        registration.addInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS,
                JerseyConfig.class.getName());
        return registration;
    }

}

Start the application and visit http://localhost:10001/app/hello/world

 2. @Path The relative path of the resource or method

If you want a Java class to be able to handle REST requests, this class must add at least one @Path("/") annotation; for methods, this annotation is optional. If you don’t add it, you will inherit the definition of the class

The value in Path can be a complex expression, such as @Path("{id}"), where {xxx} represents a template parameter. The template parameter is a wildcard defined in @Path. It  starts with  { and the middle is a A mixed string of letters and numbers (cannot contain  characters),  ending with } .

Path also supports regular expressions

The following are examples of my various types of path matching

package com.wl.jersey.resource;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

/**
 * Created by Administrator on 2019/3/23.
 */
@Path("widgets")
@Consumes(MediaType.WILDCARD)
@Produces({MediaType.APPLICATION_JSON,MediaType.TEXT_PLAIN})
public class WidgetsResource {

    //匹配路径:localhost:10001/app/widgets/(任意整数)
    @Path("{id}")
    @GET
    public String getWidget1(@PathParam("id")Integer id){
        return id + "";
    }
    //匹配路径:localhost:10001/app/widgets/(任意整数)/(任意字符)
    @Path("{id}/{name}")
    @GET
    public String getWidget2(@PathParam("id")Integer id,@PathParam("name") String name){
        return id +"-" + name;
    }

    //匹配路径:localhost:10001/app/widgets/getWidget3/(任意字符)/p
    @GET
    @Path("/getWidget3/{var}/p")
    public String getWidget3(@PathParam("var")String var){
        return var;
    }

    //匹配路径:localhost:10001/app/widgets/(任意一个或两个0-9的数值)/regex     与getWidget2有重合的匹配路径(重合的路径会匹配到正则匹配的方法下)
    //正则匹配
    //正则匹配格式     {参数名:正则表达式}  这里var为参数名称    [0-9]{1,2}为正则表达式
    @GET
    @Path("{var:[0-9]{1,2}}/regex")
    public String getWidget4(@PathParam("var")String var){
        return var;
    }

    
}

Enter http://localhost:10001/app/widgets/12 , http://localhost:10001/app/widgets/12/wl , http://localhost:10001/app/widgets/getWidget3/varhhh/p , http://localhost:10001/app/widgets/12/regex try the effect

3. Request method annotation

@GET, @PUT, @POST, @DELETE, @HEAD, @OPTIONS methods can handle HTTP request method types

4. Parameter binding annotation

@PathParam,  @QueryParam, @HeaderParam, @CookieParam,  @MatrixParam, @FormParam,@FormDataParam,@BeanParam

4.1 @PathParam is the same as the path matching example above. PathParam is to get the value of the matched path

4.2@QueryParam is to get the value of the request parameter key-value pair

4.3@HeaderParam is to get the value of the key-value pair of the request header

4.4@CookieParam is to get the value of the cookie key-value pair

4.5@MatrixParam

4.6@FormParam is to get the value of the key-value pair of the form form (application/x-www-form-urlencoded)

4.7@FormDataParam Gets the value of the key-value pair of the form (multipart/form-data)

4.8 @BeanParam directly binds the form data and other header information to the object

Below is my example use case reference https://documenter.getpostman.com/view/2537807/S17rvomr

package com.wl.jersey.resource;

import org.apache.commons.io.IOUtils;
import org.glassfish.jersey.media.multipart.FormDataParam;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import java.io.*;

/**
 * Created by Administrator on 2019/3/23.
 */
@Consumes(MediaType.WILDCARD)
@Produces({MediaType.APPLICATION_JSON,MediaType.TEXT_PLAIN})
@Path("/param")
public class ParamResource {

    //http://localhost:10001/app/param/1/wl
    @Path("{id}/{name}")
    @GET
    public String pathParam(@PathParam("id") Integer id,@PathParam("name") String name){
        return id + ":" + name;
    }

    //http://localhost:10001/app/param/queryParam?id=1&name=wl
    @Path("/queryParam")
    @GET
    public String queryParam(@QueryParam("id")Integer id,@QueryParam("name")String name){
        return id + ":" + name;
    }

    @Path("/headerParam")
    @GET
    public String headerParam(@HeaderParam("lan") String lan){
        return lan;
    }

    //http://localhost:10001/app/param/cookieParam
    @Path("/cookieParam")
    @GET
    public String cookieParam(@CookieParam("_ga")String ga, @Context HttpServletRequest request){
        return ga;
    }

    @Path("/formParam")
    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public String formParam(@FormParam("id") Integer id,@FormParam("name") String name){
        return id + ":" + name;
    }

    /**
     * 获取上传文件输入流       需要依赖
     <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-multipart</artifactId>
        <version>2.0</version>
     </dependency>
     */
    @Path("/formDataParam")
    @POST
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public String formDataParam(@FormDataParam("file")InputStream inputStream) throws IOException {
        IOUtils.copy(inputStream,new FileOutputStream(new File("123.jpg")));
        return new FileInputStream("123.jpg").available() + "";
    }

    @Path("beanParam")
    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public String beanParam(@BeanParam UserDto userDto){
        return userDto.getId() + ":" + userDto.getName();
    }

    //application/json   绑定参数最方便
    @Path("applicationJson")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public String applicationJson(UserDto userDto){
        return userDto.getId() + ":" + userDto.getName();
    }



    public static class UserDto{

        @FormParam("id")
        private Integer id;

        @FormParam("name")
        private String name;

        @HeaderParam("head")
        private String head;

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getHead() {
            return head;
        }

        public void setHead(String head) {
            this.head = head;
        }
    }



}

5. ExceptionMapper global exception capture attention to @Provider annotation

package com.wl.jersey.interceptor;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;

import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

/**
 * Created by Administrator on 2019/3/23.
 */
@Provider
public class CustomExceptionMapper implements ExceptionMapper<Throwable> {

    @Override
    public Response toResponse(Throwable exception) {
        Integer code;
        String msg;
        if(exception instanceof NotFoundException){
            //没有找到资源路径
            code = 1;
            msg = "404";
        }else if(exception instanceof JsonParseException){
            code = 2;
            msg = "json转换异常";
        }else if(exception instanceof UnrecognizedPropertyException){
            code = 3;
            msg = "";
        }else{
            code = 4;
            msg = exception.getMessage();
        }
        return Response.status(Response.Status.OK).type(MediaType.APPLICATION_JSON).entity(Result.Builder.custom(null).code(code).msg(msg).build()).build();
    }

    public static class Result<T> {
        private Integer code;

        private String msg;

        private T body;

        public Integer getCode() {
            return code;
        }

        private void setCode(Integer code) {
            this.code = code;
        }

        public String getMsg() {
            return msg;
        }

        private void setMsg(String msg) {
            this.msg = msg;
        }

        public T getBody() {
            return body;
        }

        private void setBody(T body) {
            this.body = body;
        }

        public static class Builder<T> {
            private Integer code;

            private String msg;

            private T body;

            private Builder<T> body(T body) {
                this.body = body;
                return this;
            }

            public Builder<T> code(Integer code) {
                this.code = code;
                return this;
            }

            public Builder<T> msg(String msg) {
                this.msg = msg;
                return this;
            }

            public static <T> Builder<T> custom(T body) {
                return new Builder<T>().body(body);
            }

            public Result<T> build() {
                Result<T> result = new Result<>();
                result.setBody(this.body);
                result.setCode(this.code);
                result.setMsg(this.msg);
                return result;
            }
        }
    }

}

UserResource

package com.wl.jersey.resource;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

/**
 * Created by Administrator on 2019/3/23.
 */
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.WILDCARD)
@Path(("/user"))
public class UserResource {

    @Path("/saveUser")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public UserDto saveUser(UserDto userDto){
        throw new NotFoundException("");
//        return userDto;
    }




    public static class UserDto{

        private Integer id;

        private String name;

        private String head;

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getHead() {
            return head;
        }

        public void setHead(String head) {
            this.head = head;
        }
    }
}

6. ContextResovler implements custom json serialization and deserialization of ObjectMapper objects (such as whether to allow unknown fields, whether to serialize empty fields, etc.)

package com.wl.jersey.interceptor;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import java.text.SimpleDateFormat;
import java.util.TimeZone;

/**
 * Created by Administrator on 2019/3/23.
 */
@Provider
public class JacksonConfig implements ContextResolver<ObjectMapper> {

    private static ObjectMapper mapper = new ObjectMapper();

    static{
        //允许单引号
        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES,true);
        //允许内容中含有注释符号/* 或 //
        mapper.configure(JsonParser.Feature.ALLOW_COMMENTS,true);
        //允许没有引号的属性名字
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES,true);
        //设置timeZone
        mapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

        //序列化配置
        //不包含null的属性
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,true);

        //自身引用时报错
        mapper.configure(SerializationFeature.FAIL_ON_SELF_REFERENCES,true);

        //反序列化配置
        //不允许json含有类不包含的属性
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,true);

    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return mapper;
    }

}

Because the jackson-jaxrs-base package defines two Jackson parsing exception capture classes, JsonMappingExceptionMapper and JsonParseExceptionMapper, the above CustomExceptionMapper cannot capture these two exceptions (don’t know why). Below we customize the JsonMappingExceptionMapper, JsonParseExceptionMapper exception capture classes and override the default Two

package com.wl.jersey.interceptor;

import com.fasterxml.jackson.databind.JsonMappingException;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;

/**
 * Created by Administrator on 2019/3/23.
 */
//@Provider
public class CustomJsonMappingExceptionMapper implements ExceptionMapper<JsonMappingException> {

    @Override
    public Response toResponse(JsonMappingException exception) {
        return Response
                .status(Response.Status.OK)
                .type(MediaType.APPLICATION_JSON)
                .entity(CustomExceptionMapper.Result.Builder.custom(null).code(1).msg(exception.getMessage()).build())
                .build();
    }
}
package com.wl.jersey.interceptor;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;

/**
 * Created by Administrator on 2019/3/23.
 */
public class CustomJsonParseExceptionMapper implements ExceptionMapper<JsonParseException> {
    @Override
    public Response toResponse(JsonParseException exception) {
        return Response
                .status(Response.Status.OK)
                .type(MediaType.APPLICATION_JSON)
                .entity(CustomExceptionMapper.Result.Builder.custom(null).code(1).msg(exception.getMessage()).build())
                .build();
    }
}

Note that the two classes are not annotated with @Provider. We need to manually register these two classes in JerseyConfig (I don’t know why the @Provider annotation is added or the default exception catching class cannot be overridden, which may be related to priority)

JerseyConfig is modified as follows

package com.wl.jersey.config;

import com.wl.jersey.interceptor.CustomExceptionMapper;
//import com.wl.jersey.interceptor.CustomJsonMappingExceptionMapper;
import com.wl.jersey.interceptor.CustomJsonMappingExceptionMapper;
import com.wl.jersey.interceptor.CustomJsonParseExceptionMapper;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.annotation.Configuration;

import javax.ws.rs.ApplicationPath;

/**
 * Created by Administrator on 2019/3/23.
 */
@Configuration
@ApplicationPath("/app")
public class JerseyConfig extends ResourceConfig {

    public JerseyConfig(){
        packages("com.wl");
        register(CustomJsonMappingExceptionMapper.class);
        register(CustomJsonParseExceptionMapper.class);
        //防止文件上传报错No injection source found for a parameter of type public
        register(MultiPartFeature.class);
//        register(HelloWorldResource.class);
    }


}

Below we change the request json object to illegal

First modify the id of Integer type to string type

 Add an extra field

 7.ValidationExceptionMapper validates request parameters

The jersey-bean-validation package provides us with a verification parameter exception capture class. It is very simple to implement the verification of request parameters, similar to spring-mvc

First quote

<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>5.4.3.Final</version>
    </dependency>

Modify our UserResource as follows

package com.wl.jersey.resource;

import org.hibernate.validator.constraints.NotEmpty;

import javax.validation.Valid;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.Date;

/**
 * Created by Administrator on 2019/3/23.
 */
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.WILDCARD)
@Path(("/user"))
public class UserResource {

    @Path("/saveUser")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public UserDto saveUser(@Valid UserDto userDto){
//        throw new NotFoundException("");
        return userDto;
    }

    public static class UserDto{

        private Integer id;

        private String name;

        @NotEmpty(message = "head can not be empty")
        private String head;

        private Date createTime;


        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getHead() {
            return head;
        }

        public void setHead(String head) {
            this.head = head;
        }

        public Date getCreateTime() {
            return createTime;
        }

        public void setCreateTime(Date createTime) {
            this.createTime = createTime;
        }

    }
}

We set the request parameter head to empty

 ValidationExceptionMapper returned the above data for us (there is no corresponding error message).

7.1 Implement a custom ValidationExceptionMapper

package com.wl.jersey.interceptor;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;

/**
 * Created by Administrator on 2019/3/23.
 */
public class CustomValidationExceptionMapper implements ExceptionMapper<ValidationException> {
    @Override
    public Response toResponse(ValidationException exception) {
        if (exception instanceof ConstraintViolationException) {
            final ConstraintViolationException cve = (ConstraintViolationException) exception;
            StringBuilder sb = new StringBuilder();
            Integer code = 1;
            for(ConstraintViolation cv : cve.getConstraintViolations()){
                sb.append(cv.getMessage()).append(";");
            }
            sb = sb.deleteCharAt(sb.length() - 1);
            return Response
                    .status(Response.Status.OK)
                    .type(MediaType.APPLICATION_JSON)
                    .entity(CustomExceptionMapper.Result.Builder.custom(null).code(code).msg(sb.toString()).build())
                    .build();
        }else{
            return Response
                    .status(Response.Status.OK)
                    .type(MediaType.APPLICATION_JSON)
                    .entity(CustomExceptionMapper.Result.Builder.custom(null).code(1).msg("参数校验不合格").build())
                    .build();
        }
    }
}

For the same reason, no provider annotation is added. We manually register in JerseyConfig

package com.wl.jersey.config;

import com.wl.jersey.interceptor.CustomExceptionMapper;
//import com.wl.jersey.interceptor.CustomJsonMappingExceptionMapper;
import com.wl.jersey.interceptor.CustomJsonMappingExceptionMapper;
import com.wl.jersey.interceptor.CustomJsonParseExceptionMapper;
import com.wl.jersey.interceptor.CustomValidationExceptionMapper;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.annotation.Configuration;

import javax.ws.rs.ApplicationPath;

/**
 * Created by Administrator on 2019/3/23.
 */
@Configuration
@ApplicationPath("/app")
public class JerseyConfig extends ResourceConfig {

    public JerseyConfig(){
        packages("com.wl");
        register(CustomJsonMappingExceptionMapper.class);
        register(CustomJsonParseExceptionMapper.class);
        register(CustomValidationExceptionMapper.class);
        //防止文件上传报错No injection source found for a parameter of type public
        register(MultiPartFeature.class);
//        register(HelloWorldResource.class);
    }


}

Last request again

 8.ContainerRequestFilter 与 ContainerResponseFilter

The two are similar, only the use of ContainerRequestFilter is introduced here

package com.wl.jersey.interceptor;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.ext.Provider;
import java.io.IOException;

/**
 * Created by Administrator on 2019/3/23.
 */
@Provider
public class CustomContainerRequestFilter implements ContainerRequestFilter {


    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {

    }
}

The above is a simple implementation class of ContainerRequestFilter, all requests will execute the filter method. If we want to get the HttpServletRequest object, just use the @Context annotation

@Context
    private HttpServletRequest request;

If we don’t want to request to go on, for example, if the necessary party_id is missing in the header, we only need to requestContext.abortWith to return directly to the client.

@Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        String partyId = requestContext.getHeaderString("party_id");
        if(partyId== null || partyId.equals("")){
            requestContext.abortWith(Response.status(Response.Status.OK).type(MediaType.APPLICATION_JSON).entity("partyId is null").build());
        }
    }

8.1@PreMatching annotation means to execute the filter before matching the real resource

8.2 @NameBinding annotation The above filter will match all resource paths. If we only need to match a specific resource path, we can use the @NameBinding annotation

8.3 Use of @NameBinding

Create a new annotation AuthAnnotation

package com.wl.jersey.annotation;

import javax.ws.rs.NameBinding;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by Administrator on 2019/3/23.
 */
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})  //可以放在类上也可以放在方法上
public @interface AuthAnnotation {
    
}

Modify our CustomContainerRequestFilter (add AuthAnnotaion annotation to the class)

package com.wl.jersey.interceptor;

import com.wl.jersey.annotation.AuthAnnotation;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.NameBinding;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
import java.io.IOException;

/**
 * Created by Administrator on 2019/3/23.
 */
@Provider
@AuthAnnotation
public class CustomContainerRequestFilter implements ContainerRequestFilter {

    @Context
    private HttpServletRequest request;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        String partyId = requestContext.getHeaderString("party_id");
        if(partyId== null || partyId.equals("")){
            requestContext.abortWith(Response.status(Response.Status.OK).type(MediaType.APPLICATION_JSON).entity("partyId is null").build());
        }
    }
}

Add the AuthAnnotaion annotation to the UserResource saveUser method and add a getUser resource without the AuthAnnotation annotation

package com.wl.jersey.resource;

import com.wl.jersey.annotation.AuthAnnotation;
import org.hibernate.validator.constraints.NotEmpty;

import javax.validation.Valid;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.Date;

/**
 * Created by Administrator on 2019/3/23.
 */
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.WILDCARD)
@Path(("/user"))
public class UserResource {

    @Path("/saveUser")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @AuthAnnotation
    public UserDto saveUser(@Valid UserDto userDto){
//        throw new NotFoundException("");
        return userDto;
    }

    @Path("/getUser")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public UserDto getUser(UserDto userDto){
        return userDto;
    }

    public static class UserDto{

        private Integer id;

        private String name;

        @NotEmpty(message = "head can not be empty")
        private String head;

        private Date createTime;


        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getHead() {
            return head;
        }

        public void setHead(String head) {
            this.head = head;
        }

        public Date getCreateTime() {
            return createTime;
        }

        public void setCreateTime(Date createTime) {
            this.createTime = createTime;
        }

    }
}

分别访问http://localhost:10001/app/user/saveUser 、http://localhost:10001/app/user/getUser

request

POST /app/user/saveUser HTTP/1.1
Host: localhost:10001
Content-Type: application/json
party_id: 
cache-control: no-cache
Postman-Token: 73b8c125-1f7c-4913-9c5c-84b108200ca8
{"id":"12","name":"wl","head":"asd"}------WebKitFormBoundary7MA4YWxkTrZu0gW--

response

partyId is null

request

POST /app/user/getUser HTTP/1.1
Host: localhost:10001
Content-Type: application/json
party_id: 
cache-control: no-cache
Postman-Token: 3c6a731f-de82-4be7-b7df-bb3059a82490
{"id":"12","name":"wl","head":"asd"}------WebKitFormBoundary7MA4YWxkTrZu0gW--

response

{
    "id": 12,
    "name": "wl",
    "head": "asd"
}

It can be seen that getUser does not go through the filter and saveUser executes the filter method of the filter

Reference     https://www.cnblogs.com/pixy/p/4838268.html

Guess you like

Origin blog.csdn.net/name_is_wl/article/details/88760908
Recommended