zoukankan      html  css  js  c++  java
  • Spring Boot 学习之 Web 篇(二)

    该系列并非完全原创,官方文档作者

    一、前言

    上一篇《Spring Boot 入门之基础篇(一)》介绍了 Spring Boot 的环境搭建以及项目启动打包等基础内容,本篇继续深入介绍 Spring Boot 与 Web 开发相关的知识。

    二、整合模板引擎

    由于 jsp 不被 SpringBoot 推荐使用,所以模板引擎主要介绍 Freemarker 和 Thymeleaf。

    至于这两种是什么,谷歌百度一堆介绍(我之前也不知道是什么。。。)

    1、整合Freemarker 

    添加Freemarker 依赖

    在 pom.xml 文件中添加:

    <!-- freemarker 依赖 -->
    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>

    添加 Freemarker 模板配置

    在 application.properties 中添加如下内容:

    spring.freemarker.allow-request-override=false
    spring.freemarker.cache=true
    spring.freemarker.check-template-location=true
    spring.freemarker.charset=UTF-8
    spring.freemarker.content-type=text/html
    spring.freemarker.expose-request-attributes=false
    spring.freemarker.expose-session-attributes=false
    spring.freemarker.expose-spring-macro-helpers=false
    spring.freemarker.prefix=classpath:/templates/
    spring.freemarker.suffix=.ftl

    创建FreemarkerController

    package com.phil.springboot.controller;
    
    import java.util.Map;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    @RequestMapping("freemarker")
    public class FreemarkerController {
    
    	@RequestMapping("hello")
    	public String hello(Map<String, Object> map) {
    		map.put("msg", "Hello Freemarker");
    		return "hello";
    	}
    }

    在templates 目录中创建名为 hello.ftl 文件,内容如下:

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8"/>
        <title>Document</title>
    </head>
    <body>
        <div class="container">
            <h2>${msg}</h2>
        </div>
    </body>
    </html>

    启动项目,访问localhost:8081/freemarker/hello就可以看到效果了

    2、整合 Thymeleaf

    添加 Thymeleaf 依赖

    在 pom.xml 文件中添加:

    <!-- thymeleaf 依赖 -->
    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

    添加 Thymeleaf模板配置

    在 application.properties 中添加如下内容:

    spring.thymeleaf.cache=true
    spring.thymeleaf.prefix=classpath:/templates/
    spring.thymeleaf.suffix=.html
    spring.thymeleaf.mode=HTML5
    spring.thymeleaf.encoding=UTF-8
    spring.thymeleaf.servlet.content-type=text/html

    3.0.0 版本开始会报Template Mode 'HTML5' is deprecated. Using Template Mode 'HTML' instead.,所以

    配置文件修改下

    spring.thymeleaf.mode=HTML

    创建 ThymeleafController

    package com.phil.springboot.controller;
    
    import java.util.Map;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    @RequestMapping("thymeleaf")
    public class ThymeleafController {
    
        @RequestMapping("hello")
        public String hello(Map<String,Object> map) {
            map.put("msg", "Hello Thymeleaf");
            return "hello";
        }
    }

    在 template 目录下创建名为 hello.html 的文件,内容如下:

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8"/>
        <title>Thymeleaf</title>
    </head>
    <body>
        <div class="container">
            <h2 th:text="${msg}"></h2>
        </div>
    </body>
    </html>

    三、整合Gson

    Gson对小文件处理比较快,Jackson处理大文件比较好

    1、添加依赖

    在pom.xml修改并添加:

    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-web</artifactId>
    	<exclusions>
    		<exclusion>
    			<artifactId>jackson-databind</artifactId>
    			<groupId>com.fasterxml.jackson.core</groupId>
    		</exclusion>
    	</exclusions>
    </dependency>
    <!-- gson 依赖 -->
    <dependency>
    	<groupId>com.google.code.gson</groupId>
    	<artifactId>gson</artifactId>
    </dependency>

    2、创建配置管理类

    package com.phil.springboot.config;  
      
    import java.util.List;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;  
      
    @Configuration  
    //@EnableWebMvc
    public class GsonHttpMessageConverterConfig implements WebMvcConfigurer { 
          
        @Override  
        public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
            converters.removeIf(httpMessageConverter -> httpMessageConverter instanceof MappingJackson2HttpMessageConverter); // 删除MappingJackson2HttpMessageConverter  
        }
    }  
    (如果不能正常运行,放开注释)

    3、案例演示

    实体类

    User.java

    package com.phil.springboot.bean;
    
    import java.util.Date;
    
    public class User {
    
    	private long id;
    
    	private String username;
    
    	private String password;
    
    	private Date createTime;
    
    	public long getId() {
    		return id;
    	}
    
    	public void setId(long id) {
    		this.id = id;
    	}
    
    	public String getUsername() {
    		return username;
    	}
    
    	public void setUsername(String username) {
    		this.username = username;
    	}
    
    	public String getPassword() {
    		return password;
    	}
    
    	public void setPassword(String password) {
    		this.password = password;
    	}
    
    	public Date getCreateTime() {
    		return createTime;
    	}
    
    	public void setCreateTime(Date createTime) {
    		this.createTime = createTime;
    	}
    }
    创建控制器类UserController
    package com.phil.springboot.controller;
    
    import java.util.UUID;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.phil.springboot.bean.User;
    
    @RestController
    @RequestMapping("api/user")
    public class UserController {
    	
    	@GetMapping("get/{name}")
    	public User getName(@PathVariable("name") String name) {
    		User user = new User();
    		user.setId(Math.round(Math.random()*1000));
    		user.setUsername(name);
    		user.setPassword(UUID.randomUUID().toString());
    		return user;
    	}
    }

    启动项目

    http://localhost:8081/api/user/get/a

    输出结果

    {"id":24,"username":"a","password":"f158027d-c044-459b-affd-543b374a990e"}

    四、自定义过滤器/第三方过滤器

    过滤器生效有两种方式:
    1) 使用 @Component 注解

    2) 添加到过滤器链中,此方式适用于使用第三方的过滤器。将过滤器写到总配置类中,如下

    package com.phil.springboot.config;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class FrameworkConfig {
    
    	private Logger logger = LoggerFactory.getLogger(this.getClass());
    
    	@Bean
    	public FilterRegistrationBean<TimeFilter> timeFilter() {
    		FilterRegistrationBean<TimeFilter> timeFilterRegistrationBean = new FilterRegistrationBean<>();
    		timeFilterRegistrationBean.setFilter(new TimeFilter());
    		List<String> urls = new ArrayList<>();
    		urls.add("/*");
    		timeFilterRegistrationBean.setUrlPatterns(urls);
    		return timeFilterRegistrationBean;
    	}
    	
    	class TimeFilter implements Filter {
    
    		@Override
    		public void init(FilterConfig filterConfig) throws ServletException {
    			logger.debug("=======初始化过滤器=========");
    		}
    
    		@Override
    		public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
    				throws IOException, ServletException {
    			// long start = System.currentTimeMillis();
    			filterChain.doFilter(request, response);
    			// logger.debug("filter 耗时:" + (System.currentTimeMillis() - start));
    		}
    
    		@Override
    		public void destroy() {
    			logger.debug("=======销毁过滤器=========");
    		}
    	}
    }

    热部署自动重启,控制台会输出

    2018-04-02 22:56:29.781 |-DEBUG [localhost-startStop-1] com.phil.springboot.config.FrameworkConfig$$EnhancerBySpringCGLIB$$55ea91a1 [40]  -| =======初始化过滤器=========

    五、自定义监听器

    和过滤器类似

    在FrameworkConfig.java追加

    @Bean
    public ServletListenerRegistrationBean<InitListener> servletListenerRegistrationBean() {
    	return new ServletListenerRegistrationBean<InitListener>(new InitListener());
    }
    
    class InitListener implements ServletContextListener {
    
    	@Override
    	public void contextInitialized(ServletContextEvent servletContextEvent) {
    		logger.debug("监听器初始化...");
    	}
    
    	@Override
    	public void contextDestroyed(ServletContextEvent sce) {
    	}
    }

    重新启动项目时会看到log

    还有一种方式,在入口类中实现 ServletContextInitializer,重写onStartup()方法,有兴趣去原文查看。

    六、自定义拦截器

    创建并注册拦截类

    package com.phil.springboot.config;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    public class CustomInterceptor implements WebMvcConfigurer {
    
    	@Autowired
    	private TimeInterceptor timeInterceptor;
    
    	@Override
    	public void addInterceptors(InterceptorRegistry registry) {
    		registry.addInterceptor(timeInterceptor).addPathPatterns("/**");
    	}
    }
    
    @Component
    class TimeInterceptor implements HandlerInterceptor {
    
    	@Override
    	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object,
    			Exception exception) throws Exception {
    		// logger.debug("TimeInterceptor afterCompletion");
    		// Long start = (Long) request.getAttribute("startTime");
    		// logger.debug("耗时:" + (System.currentTimeMillis() - start));
    	}
    
    	@Override
    	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object,
    			ModelAndView modelAndView) throws Exception {
    		// logger.debug("TimeInterceptor postHandle");
    		// Long start = (Long) request.getAttribute("startTime");
    		// logger.debug("耗时:" + (System.currentTimeMillis() - start));
    	}
    
    	@Override
    	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    		// logger.debug("TimeInterceptor preHandle");
    		// logger.debug(((HandlerMethod) handler).getBean().getClass().getName());
    		// logger.debug(((HandlerMethod) handler).getMethod().getName());
    		request.setAttribute("startTime", System.currentTimeMillis());
    		return true;
    	}
    }

    七、配置AOP

    1、添加依赖

    在 pom.xml 文件中添加:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

    2、创建一个切面类

    package com.phil.springboot.framewor.aop;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class TimeAspect {
    
    	private Logger logger = LoggerFactory.getLogger(this.getClass());
    	
    	@Around("execution(* com.phil.springboot.controller.UserController..*(..))")
    	
    	public Object method(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    		
    		logger.debug("=====Aspect处理=======");
    		
    		Object[] args = proceedingJoinPoint.getArgs();
    		for (Object arg : args) {
    			logger.debug("参数为:" + arg);
    		}
    		
    		long start = System.currentTimeMillis();
    		Object object = proceedingJoinPoint.proceed();
    		logger.debug("Aspect 耗时:" + (System.currentTimeMillis() - start));
    		return object;
    	}
    }

    浏览器直接输入http://localhost:8081/api/user/get/a(热部署会自动重启),控制台输出如下

    2018-04-02 23:20:24.443 |-DEBUG [http-nio-8081-exec-1] com.phil.springboot.framewor.aop.TimeAspect [20] -| =====Aspect处理=======
    2018-04-02 23:20:24.444 |-DEBUG [http-nio-8081-exec-1] com.phil.springboot.framewor.aop.TimeAspect [24] -| 参数为:a
    2018-04-02 23:20:24.450 |-DEBUG [http-nio-8081-exec-1] com.phil.springboot.framewor.aop.TimeAspect [29] -| Aspect 耗时:6

    八、CORS 支持(跨域)

    我目前的写法,刚开始用也没人说哪种写法好,自认为这种很方法(前端是8082端口,后端是8081)

    前端写法

     <script type="text/javascript">
        $(function() {
            $("#test").on("click", function() {
                $.ajax({
                    "url": "http://localhost:8081/api/user",
                    "type": "get",
                    "dataType": "json",
                    "success": function(data) {
                        console.log(data);
                    }
                })
            });
        });
        </script>
    后端
    package com.phil.springboot.controller;
    
    import java.util.UUID;
    
    import org.springframework.web.bind.annotation.CrossOrigin;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.phil.springboot.bean.User;
    
    @RestController
    @RequestMapping("api/user")
    @CrossOrigin(origins="http://localhost:8081")
    public class UserController {
    	
    	@GetMapping("get/{name}")
    	public User getName(@PathVariable("name") String name) {
    		User user = new User();
    		user.setId(Math.round(Math.random()*1000));
    		user.setUsername(name);
    		user.setPassword(UUID.randomUUID().toString());
    		return user;
    	}
    }

    贴出原文另外两种写法

    @Configuration
    public class WebConfig {
        
        @Bean
        public WebMvcConfigurer corsConfigurer() {
            return new WebMvcConfigurerAdapter() {
              @Override
              public void addCorsMappings(CorsRegistry registry) {
                  registry.addMapping("/fastjson/**")
                          .allowedOrigins("http://localhost:8088");// 允许 8088 端口访问
              }
            };
        }
    }
    
    @Configuration
    public class WebConfig extends WebMvcConfigurerAdapter{
        
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/fastjson/**")
                  .allowedOrigins("http://localhost:8088");// 允许 8088 端口访问
        }
    }

    九、整合JavaMail

    使用 Freemark 实现邮件的模板

    1、添加依赖

    在pom.xml文件中添加

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
    

    Freemark 依赖之前已添加

    2、添加配置

    如果不同环境的邮箱不一样的话,可以分别在application-*.properties中添加

    在application-local.properties 中添加(查看MailProperties.class源码)

    spring.mail.host=smtp.sina.com
    spring.mail.username=jjff@sina.cn
    spring.mail.password=xxxx
    spring.mail.properties.mail.smtp.auth=true
    spring.mail.properties.mail.smtp.starttls.enable=true
    spring.mail.properties.mail.smtp.starttls.required=true

    3、创建邮件实体类

    package com.phil.springboot.mail;
    
    public class EmailEntity {
    
    	private String personal;
    
    	private String receiver;
    
    	private String subject;
    
    	private String text;
    
    	private String content;
    
    	public String getPersonal() {
    		return personal;
    	}
    
    	public void setPersonal(String personal) {
    		this.personal = personal;
    	}
    
    	public String getReceiver() {
    		return receiver;
    	}
    
    	public void setReceiver(String receiver) {
    		this.receiver = receiver;
    	}
    
    	public String getSubject() {
    		return subject;
    	}
    
    	public void setSubject(String subject) {
    		this.subject = subject;
    	}
    
    	public String getText() {
    		return text;
    	}
    
    	public void setText(String text) {
    		this.text = text;
    	}
    
    	public String getContent() {
    		return content;
    	}
    
    	public void setContent(String content) {
    		this.content = content;
    	}
    }

    4、创建配置类

    package com.phil.springboot.mail;
    
    import java.io.UnsupportedEncodingException;
    import java.util.Map;
    
    import javax.mail.MessagingException;
    import javax.mail.internet.InternetAddress;
    import javax.mail.internet.MimeMessage;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.mail.MailProperties;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.mail.javamail.JavaMailSender;
    import org.springframework.mail.javamail.MimeMessageHelper;
    import org.springframework.stereotype.Component;
    import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
    import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
    
    @Component
    @EnableConfigurationProperties(MailProperties.class)
    public class EmailConfig {
    
    	@Autowired
    	private MailProperties mailProperties;
    
    	@Autowired
    	private JavaMailSender javaMailSender;
    
    	@Autowired
    	private FreeMarkerConfigurer freeMarkerConfigurer;
    
    	private String sendTextMail(EmailEntity email) throws MessagingException, UnsupportedEncodingException {
    		MimeMessage message = javaMailSender.createMimeMessage();
    		MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
    		InternetAddress from = new InternetAddress();
    		from.setAddress(mailProperties.getUsername());
    		from.setPersonal(email.getPersonal());
    		helper.setFrom(from);
    		String receiver = email.getReceiver();
    		String receivers[] = receiver.split(";");
    		helper.setTo(receivers);
    		helper.setSubject(email.getSubject());
    		helper.setText(email.getText(), true);
    		javaMailSender.send(message);
    		return email.getText();
    	}
    	
    	public void sendText(EmailEntity email) {
    		try {
    			this.sendTextMail(email);
    		} catch (UnsupportedEncodingException e) {
    			e.printStackTrace();
    		} catch (MessagingException e) {
    			e.printStackTrace();
    		}
    	}
    
    	public String getTextByTemplate(String template, Map<String, Object> model) throws Exception {
    		return FreeMarkerTemplateUtils
    				.processTemplateIntoString(freeMarkerConfigurer.getConfiguration().getTemplate(template), model);
    	}
    }

    5、创建测试接口

    package com.phil.springboot.mail;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.phil.springboot.util.PhilUtil;
    
    import io.swagger.annotations.Api;
    
    @RestController
    @RequestMapping("/api/email")
    @Api("发送Email接口")
    public class EmailController {
    
    	private Logger logger = LoggerFactory.getLogger(this.getClass());
    
    	@Autowired
    	private EmailConfig emailConfig;
    
    	@GetMapping("send/{receiver}")
    	public void testEmailConfig(@PathVariable("receiver") String receiver) {
    		Map<String, Object> map = new HashMap<String, Object>();
    		EmailEntity email = new EmailEntity();
    		email.setReceiver(receiver + ".com");
    		email.setContent("测试内容");
    		email.setSubject("测试邮件");
    		try {
    			map = PhilUtil.objectToMap(email);
    			String templatePath = "mail.ftl";
    			String text = emailConfig.getTextByTemplate(templatePath, map);
    			// 发送
    			email.setText(text);
    			emailConfig.sendText(email);
    			logger.debug("successful to send message!");
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    (写的很low,看官看着改下)

    如果出现STARTTLS is required but host does not support STARTTLS报错,修改如下配置

    spring.mail.properties.mail.smtp.starttls.enable=false
    spring.mail.properties.mail.smtp.starttls.required=false

    或者写个单元测试,在pom.xml文件中添加

    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-test</artifactId>
    	<scope>test</scope>
    </dependency>

    单元测试类

    package com.phil.springboot.mail;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import com.phil.springboot.util.PhilUtil;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class MailTest {
    	
    	private Logger logger = LoggerFactory.getLogger(this.getClass());
    
    	@Autowired
    	private EmailConfig emailConfig;
    
    	@Test
    	public void testEmailConfig() {
    		Map<String, Object> map = new HashMap<String, Object>();
    		EmailEntity email = new EmailEntity();
    		email.setReceiver("phil.jing@msn.com");
    		email.setContent("测试内容");
    		email.setSubject("测试邮件");
    		try {
    			map = PhilUtil.objectToMap(email);
    			String templatePath = "mail.ftl";
    			String text = emailConfig.getTextByTemplate(templatePath, map);
    			// 发送
    			email.setText(text);
    			emailConfig.sendText(email);
    			logger.debug("successful to send message!");
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }

    控制台输出

    2018-04-03 11:47:19.177 |-INFO  [main] com.phil.springboot.mail.MailTest [57] -| Started MailTest in 4.652 seconds (JVM running for 5.501)
    2018-04-03 11:47:23.129 |-DEBUG [main] com.phil.springboot.mail.MailTest [39] -| successful to send message!

    十、整合 Swagger2

    因为我用Gson替代的Jackson,也没用FastJson,几经波折

    1、修改并添加pom.xml

    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-web</artifactId>
    	<!-- <exclusions>
    		<exclusion>
    			<artifactId>jackson-databind</artifactId>
    			<groupId>com.fasterxml.jackson.core</groupId>
    		</exclusion>
    	</exclusions> -->
    </dependency>
    <!-- swagger2 依賴 -->
    <dependency>
    	<groupId>io.springfox</groupId>
    	<artifactId>springfox-swagger2</artifactId>
    	<version>2.8.0</version>
    </dependency>
    <dependency>
    	<groupId>io.springfox</groupId>
    	<artifactId>springfox-swagger-ui</artifactId>
    	<version>2.8.0</version>
    </dependency>

    2、创建Adapter

    package com.phil.springboot.framewor.adapter;
    
    import java.lang.reflect.Type;
    
    import com.google.gson.JsonElement;
    import com.google.gson.JsonParser;
    import com.google.gson.JsonSerializationContext;
    import com.google.gson.JsonSerializer;
    
    import springfox.documentation.spring.web.json.Json;
    
    public class SpringfoxJsonToGsonAdapter implements JsonSerializer<Json> {
    
    	@Override
        public JsonElement serialize(Json json, Type type, JsonSerializationContext context) {
            final JsonParser parser = new JsonParser();
            return parser.parse(json.value());
        }
    } 
    

    3、修改GsonHttpMessageConverterConfig 

    package com.phil.springboot.config;
    
    import java.lang.reflect.Type;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.converter.json.GsonHttpMessageConverter;
    
    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    import com.google.gson.JsonElement;
    import com.google.gson.JsonPrimitive;
    import com.google.gson.JsonSerializationContext;
    import com.google.gson.JsonSerializer;
    import com.phil.springboot.framework.adapter.SpringfoxJsonToGsonAdapter;
    
    import springfox.documentation.spring.web.json.Json;
    
    @Configuration
    public class GsonHttpMessageConverterConfig {
    
    	@Bean
    	public GsonHttpMessageConverter gsonHttpMessageConverter() {
    		GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
    		converter.setGson(gson());
    		return converter;
    	}
    
    	private Gson gson() {
    		final GsonBuilder builder = new GsonBuilder();
    		builder.registerTypeAdapter(Json.class, new SpringfoxJsonToGsonAdapter());	
    		builder.registerTypeAdapter(Double.class, new JsonSerializer<Double>() { 
    			 @Override
    			 public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) {
    			  if(src == src.longValue()){
    				  return new JsonPrimitive(src.longValue());   
    			   } else if (src == src.intValue()) {
    				   return new JsonPrimitive(src.intValue());
    			   }
    			  return new JsonPrimitive(src);
    			 }
    			 });
    		return builder.create();
    	}
    }

    4、创建Swagger2配置类

    package com.phil.springboot.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.context.request.async.DeferredResult;
    
    import springfox.documentation.builders.ApiInfoBuilder;
    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;
    
    @Configuration
    @EnableSwagger2
    public class Swagger2Configuration {
    
    	@Bean
    	public Docket api() {
    		return new Docket(DocumentationType.SWAGGER_2)	
    //				.groupName(groupName)	
                    .genericModelSubstitutes(DeferredResult.class)
                    .useDefaultResponseMessages(false)
                    .forCodeGeneration(true)
                    .pathMapping("/")
                    .select()
                    .build()
                    .apiInfo(apiInfo());
    	}
    	
    	private ApiInfo apiInfo() {
    		return new ApiInfoBuilder()//
    				.title("Spring Boot 之 Web 篇")// 标题
    				.description("spring boot Web 相关内容")// 描述
    				.contact(new Contact("phil", "https://blog.csdn.net/phil_jing", "phil.jing@msn.com"))// 联系
    				.version("1.0")// 版本
    				.build();
    	}
    
    }

    为了能更好的说明接口信息,还可以在 Controller 类上使用 Swagger2 相关注解说明信息。

    package com.phil.springboot.controller;
    
    import java.util.UUID;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.phil.springboot.bean.User;
    
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiImplicitParam;
    import io.swagger.annotations.ApiOperation;
    
    @Api(value = "API测试", tags = { "测试接口" })
    @RestController
    @RequestMapping("api/user")
    public class UserController {
    	
    	@ApiOperation("获取用户信息")
    	@ApiImplicitParam(name = "name", value = "用户名", dataType = "string", paramType = "query")
    	@GetMapping("/get/{name}")
    	public User getName(@PathVariable("name") String name) {
    		User user = new User();
    		user.setId(Math.round(Math.random()*1000));
    		user.setUsername(name);
    		user.setPassword(UUID.randomUUID().toString());
    		return user;
    	}
    }

    注意,上边的方法是用 @GetMapping 注解,如果只是使用 @RequestMapping 注解,不配置 method 属性,那么 API 文档会生成 7 种请求方式。

    (在SpringfoxJsonToGsonAdapter的serialize()方法打个断点),然后debug启动,浏览器输入http://localhost:8081/swagger-ui.html或者http://localhost:8081/v2/api-docs,这时候会发现进入断点了,而不是用原来的Jackson了。


    本文为Phil Jing原创文章,未经博主允许不得转载,如有问题请直接回复或者加群。
  • 相关阅读:
    Java 工程名上有个红色叹号
    TestNG 入门教程
    字典序问题
    统计数字问题
    sniffer 简介
    【转】IE浏览器快捷键大全
    批处理 延时不完全总结【转】
    批处理(Batch)---批处理脚本。
    windows系统命令行
    计算机网络
  • 原文地址:https://www.cnblogs.com/phil_jing/p/15615867.html
Copyright © 2011-2022 走看看