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了。


posted @ 2018-04-28 20:23  phil_jing  Views(63)  Comments(0Edit  收藏  举报