diff --git a/47.Spring-Boot-Content-Negotiation/pom.xml b/47.Spring-Boot-Content-Negotiation/pom.xml new file mode 100644 index 0000000..06b47b8 --- /dev/null +++ b/47.Spring-Boot-Content-Negotiation/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.0.RELEASE + + + com.example + demo + 0.0.1-SNAPSHOT + demo + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/DemoApplication.java b/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/DemoApplication.java new file mode 100644 index 0000000..094d95b --- /dev/null +++ b/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/DemoApplication.java @@ -0,0 +1,13 @@ +package com.example.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DemoApplication { + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/config/WebConfigurer.java b/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/config/WebConfigurer.java new file mode 100644 index 0000000..07f8418 --- /dev/null +++ b/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/config/WebConfigurer.java @@ -0,0 +1,57 @@ +package com.example.demo.config; + +import com.example.demo.converter.PropertiesHttpMessageConverter; +import com.example.demo.handler.PropertiesHandlerMethodReturnValueHandler; +import com.example.demo.resolver.PropertiesHandlerMethodArgumentResolver; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.HandlerMethodReturnValueHandler; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.List; + +/** + * @author MrBird + */ +@Configuration +public class WebConfigurer implements WebMvcConfigurer { + + + @Autowired + private RequestMappingHandlerAdapter requestMappingHandlerAdapter; + + @PostConstruct + public void init() { + // 获取当前 RequestMappingHandlerAdapter 所有的 ArgumentResolver对象 + List argumentResolvers = requestMappingHandlerAdapter.getArgumentResolvers(); + List newArgumentResolvers = new ArrayList<>(argumentResolvers.size() + 1); + // 添加 PropertiesHandlerMethodArgumentResolver 到集合第一个位置 + newArgumentResolvers.add(0, new PropertiesHandlerMethodArgumentResolver()); + // 将原 ArgumentResolver 添加到集合中 + newArgumentResolvers.addAll(argumentResolvers); + // 重新设置 ArgumentResolver对象集合 + requestMappingHandlerAdapter.setArgumentResolvers(newArgumentResolvers); + + // 获取当前 RequestMappingHandlerAdapter 所有的 returnValueHandlers对象 + List returnValueHandlers = requestMappingHandlerAdapter.getReturnValueHandlers(); + List newReturnValueHandlers = new ArrayList<>(returnValueHandlers.size() + 1); + // 添加 PropertiesHandlerMethodReturnValueHandler 到集合第一个位置 + newReturnValueHandlers.add(0, new PropertiesHandlerMethodReturnValueHandler()); + // 将原 returnValueHandlers 添加到集合中 + newReturnValueHandlers.addAll(returnValueHandlers); + // 重新设置 ReturnValueHandlers对象集合 + requestMappingHandlerAdapter.setReturnValueHandlers(newReturnValueHandlers); + } + + public void extendMessageConverters(List> converters) { + // converters.add(new PropertiesHttpMessageConverter()); + // 指定顺序,这里为第一个 + converters.add(0, new PropertiesHttpMessageConverter()); + } + +} diff --git a/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/controller/TestController.java b/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/controller/TestController.java new file mode 100644 index 0000000..eb815f9 --- /dev/null +++ b/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/controller/TestController.java @@ -0,0 +1,29 @@ +package com.example.demo.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Properties; + +/** + * @author MrBird + */ +// @RestController +@Controller +public class TestController { + + @GetMapping(value = "test", consumes = "text/properties") + @ResponseBody + public Properties getUser(@RequestBody Properties properties) { + return properties; + } + + @GetMapping(value = "test1", consumes = "text/properties") + // @ResponseBody + public Properties getUser1(Properties properties) { + return properties; + } +} diff --git a/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/converter/PropertiesHttpMessageConverter.java b/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/converter/PropertiesHttpMessageConverter.java new file mode 100644 index 0000000..07288d7 --- /dev/null +++ b/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/converter/PropertiesHttpMessageConverter.java @@ -0,0 +1,73 @@ +package com.example.demo.converter; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpInputMessage; +import org.springframework.http.HttpOutputMessage; +import org.springframework.http.MediaType; +import org.springframework.http.converter.AbstractGenericHttpMessageConverter; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.http.converter.HttpMessageNotWritableException; + +import java.io.*; +import java.lang.reflect.Type; +import java.nio.charset.Charset; +import java.util.Properties; + +/** + * @author MrBird + */ +public class PropertiesHttpMessageConverter extends AbstractGenericHttpMessageConverter { + + public PropertiesHttpMessageConverter() { + super(new MediaType("text", "properties")); + } + + @Override + protected void writeInternal(Properties properties, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { + // 获取请求头 + HttpHeaders headers = outputMessage.getHeaders(); + // 获取 content-type + MediaType contentType = headers.getContentType(); + // 获取编码 + Charset charset = null; + if (contentType != null) { + charset = contentType.getCharset(); + } + + charset = charset == null ? Charset.forName("UTF-8") : charset; + + // 获取请求体 + OutputStream body = outputMessage.getBody(); + OutputStreamWriter outputStreamWriter = new OutputStreamWriter(body, charset); + + properties.store(outputStreamWriter, "Serialized by PropertiesHttpMessageConverter#writeInternal"); + } + + @Override + protected Properties readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { + Properties properties = new Properties(); + // 获取请求头 + HttpHeaders headers = inputMessage.getHeaders(); + // 获取 content-type + MediaType contentType = headers.getContentType(); + // 获取编码 + Charset charset = null; + if (contentType != null) { + charset = contentType.getCharset(); + } + + charset = charset == null ? Charset.forName("UTF-8") : charset; + + // 获取请求体 + InputStream body = inputMessage.getBody(); + InputStreamReader inputStreamReader = new InputStreamReader(body, charset); + + properties.load(inputStreamReader); + return properties; + } + + @Override + public Properties read(Type type, Class contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { + return readInternal(null, inputMessage); + } +} diff --git a/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/handler/PropertiesHandlerMethodReturnValueHandler.java b/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/handler/PropertiesHandlerMethodReturnValueHandler.java new file mode 100644 index 0000000..f1f9864 --- /dev/null +++ b/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/handler/PropertiesHandlerMethodReturnValueHandler.java @@ -0,0 +1,58 @@ +package com.example.demo.handler; + +import org.springframework.core.MethodParameter; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.server.ServletServerHttpResponse; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.context.request.ServletWebRequest; +import org.springframework.web.method.support.HandlerMethodReturnValueHandler; +import org.springframework.web.method.support.ModelAndViewContainer; + +import javax.servlet.http.HttpServletResponse; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.nio.charset.Charset; +import java.util.Properties; + +/** + * @author MrBird + */ +public class PropertiesHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler { + + @Override + public boolean supportsReturnType(MethodParameter returnType) { + return Properties.class.equals(returnType.getMethod().getReturnType()); + } + + @Override + public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { + Properties properties = (Properties) returnValue; + + ServletWebRequest servletWebRequest = (ServletWebRequest) webRequest; + + HttpServletResponse response = servletWebRequest.getResponse(); + ServletServerHttpResponse servletServerHttpResponse = new ServletServerHttpResponse(response); + + // 获取请求头 + HttpHeaders headers = servletServerHttpResponse.getHeaders(); + + MediaType contentType = headers.getContentType(); + // 获取编码 + Charset charset = null; + if (contentType != null) { + charset = contentType.getCharset(); + } + + charset = charset == null ? Charset.forName("UTF-8") : charset; + + // 获取请求体 + OutputStream body = servletServerHttpResponse.getBody(); + OutputStreamWriter outputStreamWriter = new OutputStreamWriter(body, charset); + + properties.store(outputStreamWriter, "Serialized by PropertiesHandlerMethodReturnValueHandler#handleReturnValue"); + + // 告诉 Spring MVC 请求已经处理完毕 + mavContainer.setRequestHandled(true); + } +} diff --git a/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/resolver/PropertiesHandlerMethodArgumentResolver.java b/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/resolver/PropertiesHandlerMethodArgumentResolver.java new file mode 100644 index 0000000..e10d302 --- /dev/null +++ b/47.Spring-Boot-Content-Negotiation/src/main/java/com/example/demo/resolver/PropertiesHandlerMethodArgumentResolver.java @@ -0,0 +1,44 @@ +package com.example.demo.resolver; + +import org.springframework.core.MethodParameter; +import org.springframework.http.MediaType; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.context.request.ServletWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +import javax.servlet.http.HttpServletRequest; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.util.Properties; + +/** + * @author MrBird + */ +public class PropertiesHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { + @Override + public boolean supportsParameter(MethodParameter parameter) { + return Properties.class.equals(parameter.getParameterType()); + } + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + ServletWebRequest servletWebRequest = (ServletWebRequest) webRequest; + HttpServletRequest request = servletWebRequest.getRequest(); + String contentType = request.getHeader("Content-Type"); + + MediaType mediaType = MediaType.parseMediaType(contentType); + // 获取编码 + Charset charset = mediaType.getCharset() == null ? Charset.forName("UTF-8") : mediaType.getCharset(); + // 获取输入流 + InputStream inputStream = request.getInputStream(); + InputStreamReader inputStreamReader = new InputStreamReader(inputStream, charset); + + // 输入流转换为 Properties + Properties properties = new Properties(); + properties.load(inputStreamReader); + return properties; + } +} diff --git a/47.Spring-Boot-Content-Negotiation/src/main/resources/application.properties b/47.Spring-Boot-Content-Negotiation/src/main/resources/application.properties new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/47.Spring-Boot-Content-Negotiation/src/main/resources/application.properties @@ -0,0 +1 @@ + diff --git a/47.Spring-Boot-Content-Negotiation/src/test/java/com/example/demo/DemoApplicationTests.java b/47.Spring-Boot-Content-Negotiation/src/test/java/com/example/demo/DemoApplicationTests.java new file mode 100644 index 0000000..480d1ca --- /dev/null +++ b/47.Spring-Boot-Content-Negotiation/src/test/java/com/example/demo/DemoApplicationTests.java @@ -0,0 +1,16 @@ +package com.example.demo; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class DemoApplicationTests { + + @Test + public void contextLoads() { + } + +}