Spring MVC의 유연한 제어 json 반환 문제(사용자 정의 필터 필드)

11374 단어 springmvcjson
이 글은 주로 Spring MVC가 Json 데이터를 어떻게 동적으로 되돌려주는지 이야기한다. 우리가 웹 인터페이스 개발을 할 때 이런 장면을 자주 볼 수 있다.
두 개의 요청은 같은 대상을 되돌려주지만 필요한 되돌려 주기 필드는 같지 않습니다.아래 장면

/**
*  Id
*/
@RequestMapping("list")
@ResponseBody
public List<Article> findAllNameAndId() {
 return articleService.findAll();
}

/**
*  
*/
@RequestMapping("list-detail")
@ResponseBody
public List<Article> findAllDetail() {
 return articleService.findAll();
}
Spring MVC는 기본적으로 json 프레임워크를 jackson으로 전환합니다.여러분도 아시다시피 jackson은 실체 클래스에 주석을 붙여서 서열화 규칙을 지정할 수 있지만 그렇게 하면 비교적 유연하지 않아서 우리가 현재 달성하고자 하는 이런 상황을 실현할 수 없습니다.
이 글은 주로 사용자 정의 주석을 통해 더욱 유연하고 세립화 제어 json 형식의 전환을 말한다.
결국 우리는 다음과 같은 효과를 실현해야 한다.

@RequestMapping(value = "{id}", method = RequestMethod.GET)
//   filter   createTime, updateTime  
@JSON(type = Article.class, filter="createTime,updateTime") 
public Article get(@PathVariable String id) {
  return articleService.get(id);
}
@RequestMapping(value="list", method = RequestMethod.GET)
//   include   id, name   
@JSON(type = Article.class , include="id,name")
public List<Article> findAll() {
  return articleService.findAll();
}
jackson 프로그래밍 필터 필드
jackson에서 우리는 실체 클래스에 @JsonFilter 주석을 추가하고 ObjectMapper를 통과할 수 있습니다.필터 규칙 설정을 위한 setFilterProvider여기서 setFilter Provider의 사용에 대해 간단히 설명해 드리겠습니다.

@JsonFilter("ID-TITLE")
class Article {
 private String id;
 private String title;
 private String content;
 // ... getter/setter
}

// Demo
class Demo {
 public void main(String args[]) {
  ObjectMapper mapper = new ObjectMapper();
  // SimpleBeanPropertyFilter.filterOutAllExcept("id,title")
  //   id,title  , ,  id   title
  mapper.setFilterProvider(new SimpleFilterProvider().addFilter("ID-TITLE",
          SimpleBeanPropertyFilter.filterOutAllExcept("id,title"))); 

  String filterOut = mapper.writeValueAsString(new Article());

  mapper = new ObjectMapper();
  // SimpleBeanPropertyFilter.serializeAllExcept("id,title")
  //  ,  id   title,  id   title ,  json
  mapper.setFilterProvider(new SimpleFilterProvider().addFilter("ID-TITLE",
      SimpleBeanPropertyFilter.serializeAllExcept(filter.split("id,title"))));

  String serializeAll = mapper.writeValueAsString(new Article());

  System.out.println("filterOut:" + filterOut);
  System.out.println("serializeAll :" + serializeAll);  
 }
}
결과 내보내기

filterOut:{id: "", title: ""}
serializeAll:{content:""}
포장 json 변환
위의 코드를 통해 setFilterProvider를 사용하여 필터가 필요한 필드를 유연하게 처리할 수 있음을 알 수 있습니다.그러나 상기 방법의 일부 결함은 원래의 모델에 주석을 달아야 한다는 것이다. 여기서 우리는 ObjectMapper를 사용한다.ddMixIn(Class type, Class mixinType) 방법입니다. 이 방법은 두 종류의 주석을 혼합하여 첫 번째 파라미터의 클래스가 두 번째 파라미터 클래스의 주석을 가질 수 있도록 하는 것입니다.필터가 필요한 모델과 @JsonFilter 메모의 결합 해제

package diamond.cms.server.json;

import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;

/**
 * depend on jackson
 * @author Diamond
 */
public class CustomerJsonSerializer {

  static final String DYNC_INCLUDE = "DYNC_INCLUDE";
  static final String DYNC_FILTER = "DYNC_FILTER";
  ObjectMapper mapper = new ObjectMapper();

  @JsonFilter(DYNC_FILTER)
  interface DynamicFilter {
  }

  @JsonFilter(DYNC_INCLUDE)
  interface DynamicInclude {
  }

  /**
   * @param clazz  Class
   * @param include  
   * @param filter  
   */
  public void filter(Class<?> clazz, String include, String filter) {
    if (clazz == null) return;
    if (include != null && include.length() > 0) {
      mapper.setFilterProvider(new SimpleFilterProvider().addFilter(DYNC_INCLUDE,
          SimpleBeanPropertyFilter.filterOutAllExcept(include.split(","))));
      mapper.addMixIn(clazz, DynamicInclude.class);
    } else if (filter !=null && filter.length() > 0) {
      mapper.setFilterProvider(new SimpleFilterProvider().addFilter(DYNC_FILTER,
          SimpleBeanPropertyFilter.serializeAllExcept(filter.split(","))));
      mapper.addMixIn(clazz, DynamicFilter.class);
    }
  }

  public String toJson(Object object) throws JsonProcessingException {
    return mapper.writeValueAsString(object);
  }
}
우리 이전의 데모는 다음과 같이 변할 수 있다.

// Demo
class Demo {
 public void main(String args[]) {
  CustomerJsonSerializer cjs= new CustomerJsonSerializer();
  //   Article  ,  id, name
  cjs.filter(Article.class, "id,name", null); 

  String include = cjs.toJson(new Article()); 

  cjs = new CustomerJsonSerializer();
  //   Article  ,  id, name
  cjs.filter(Article.class, null, "id,name"); 

  String filter = cjs.toJson(new Article());

  System.out.println("include: " + include);
  System.out.println("filter: " + filter);  
 }
}
결과 내보내기

include: {id: "", title: ""}
filter: {content:""}
사용자 정의 @JSON 메모
우리는 문장의 시작과 같은 효과를 실현해야 한다.여기에 주석을 사용자 정의했습니다. 방법에 추가할 수 있습니다. 이 주석은Customer Json Serializer에 파라미터를 휴대하는 데 사용됩니다.filter 방법은 어떤 종류의 일부 필드를 필터하거나 포함해야 한다는 것입니다.

package diamond.cms.server.json;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface JSON {
  Class<?> type();
  String include() default "";
  String filter() default "";
}
Spring MVC를 위한 HandlerMethodReturnValueHandler
HandlerMethodReturnValueHandler 인터페이스 Spring MVC는 요청 반환 값을 처리하는 데 사용됩니다.이 인터페이스의 정의와 설명을 보십시오. 인터페이스는 두 가지 방법이 있습니다.supportsReturn Type은 처리 클래스가 현재 요청을 지원하는지 판단하는 데 사용됩니다.handleReturn Value는 구체적인 논리적 실현입니다.

 // Spring MVC  
package org.springframework.web.method.support;

import org.springframework.core.MethodParameter;
import org.springframework.web.context.request.NativeWebRequest;

public interface HandlerMethodReturnValueHandler {

  boolean supportsReturnType(MethodParameter returnType);

  void handleReturnValue(Object returnValue, MethodParameter returnType,
      ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;

}

저희가 평소에 @ResponseBody를 사용하는데 Request ResponseBody Method Processor 같은 종류에 맡기는 거예요.
그리고 저희가 Model AndView로 돌아왔을 때 Model AndView Method Return Value Handler 클래스에서 처리했습니다.
글의 시작 효과를 실현하기 위해 저는 Json Return Handler 클래스를 실현했습니다. 방법이 @JSON 주석이 있을 때 이 클래스를 사용하여 반환 값을 처리합니다.

package diamond.cms.server.json.spring;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import diamond.cms.server.json.CustomerJsonSerializer;
import diamond.cms.server.json.JSON;

public class JsonReturnHandler implements HandlerMethodReturnValueHandler{

  @Override
  public boolean supportsReturnType(MethodParameter returnType) { 
    //   JSON    Handler  
    boolean hasJsonAnno= returnType.getMethodAnnotation(JSON.class) != null;
    return hasJsonAnno;
  }

  @Override
  public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer,
      NativeWebRequest webRequest) throws Exception {
    //  , 
    mavContainer.setRequestHandled(true);

    //  filter   
    HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
    Annotation[] annos = returnType.getMethodAnnotations();
    CustomerJsonSerializer jsonSerializer = new CustomerJsonSerializer();
    Arrays.asList(annos).forEach(a -> {
      if (a instanceof JSON) {
        JSON json = (JSON) a;
        jsonSerializer.filter(json.type(), json.include(), json.filter());
      }
    });

    response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
    String json = jsonSerializer.toJson(returnValue);
    response.getWriter().write(json);
  }
}

이를 통해 우리는 최종적으로 다음과 같은 효과를 실현할 수 있다.

class Article {
 private String id;
 private String title;
 private String content;
 private Long createTime;
 // ... getter/setter
}

@Controller
@RequestMapping("article")
class ArticleController {
 @RequestMapping(value = "{id}", method = RequestMethod.GET)
 @JSON(type = Article.class, filter="createTime") 
 public Article get(@PathVariable String id) {
   return articleService.get(id);
 }

 @RequestMapping(value="list", method = RequestMethod.GET)
 @JSON(type = Article.class , include="id,title")
 public List<Article> findAll() {
   return articleService.findAll();
 }
}

요청/article/{articleId}

{
  id: "xxxx",
  title: "xxxx",
  content: "xxxx"
}
article/list 요청

[ {id: "xx", title: ""}, {id: "xx", title: ""}, {id: "xx", title: ""} ... ]
다운로드 주소:cms-admin-end_jb51.rar
이상은 본문의 전체 내용입니다. 여러분의 학습에 도움이 되고 저희를 많이 응원해 주십시오.

좋은 웹페이지 즐겨찾기