1. 程式人生 > >Spring Boot 學習之 Web 篇(二)

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
[email protected]
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("[email protected]");
		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!

因為我用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", "[email protected]"))// 聯絡
				.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了。

相關推薦

Spring Boot 學習 Web

該系列並非完全原創,官方文件、作者一、前言上一篇《Spring Boot 入門之基礎篇(一)》介紹了 Spring Boot 的環境搭建以及專案啟動打包等基礎內容,本篇繼續深入介紹 Spring Boot 與 Web 開發相關的知識。二、整合模板引擎由於 jsp 不被 Spr

Spring Boot 入門 Web

一、前言 上一篇《Spring Boot 入門之基礎篇(一)》介紹了 Spring Boot 的環境搭建以及專案啟動打包等基礎內容,本篇繼續深入介紹 Spring Boot 與 Web 開發相關的知識。 二、整合模板引擎 由於 jsp 不被 SpringBoot 推薦使用,所以模板引擎主

Spring Boot 學習基礎

該系列並非完全原創,官方文件、作者Spring Boot 是由 Pivotal 團隊提供的全新框架,其設計目的是用來簡化新 Spring 應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。一、環境搭建建立一個Maven專案,

Spring Boot 入門基礎

一、前言 Spring Boot 是由 Pivotal 團隊提供的全新框架,其設計目的是用來簡化新 Spring 應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。 本系列以快速入門為主,可當作工具小手冊閱讀

Spring Boot學習旅:springboot 整合 fastjson

springboot 預設使用的 jackson 但是聽說某寶的fastjson 效能很好,而且平時用的習慣,所以來整合一下。 首先在pom 中匯入依賴 <dependency> <groupId>

Spring Boot學習筆記----mybatis註解

之前的博文講述了mybatis註解的簡單用法,包括@Select,@Insert,@Update,@Delete,@Result,@Param和@Options。本文將記錄多個Provider的用法。 如何理解Provider呢?只是換了一種形式。將原來的SQ

Sping Boot入門到實戰實戰:一些常用功能的Spring Boot Starters

包含功能 阿里雲訊息服務MNS 阿里雲訊息佇列服務(即時訊息、延遲訊息、事務訊息) AOP日誌 基於MyBatis通用Mapper及DRUID的資料庫訪問 dubbo支援 錯誤處理 七牛圖片服務 redis多連線池支援 swagger配置 跨域配置 原始碼地址:https://github.com/ron

Spring Boot 揭秘與實戰 數據存儲 - 聲明式事務管理

public rollback long tar jpa oid config 新的 autowire 文章目錄 1. 聲明式事務 2. Spring Boot默認集成事務 3. 實戰演練4. 源代碼 3.1. 實體對象 3.2. DAO 相關 3.3. Service

spring boot 學習路3 集成mybatis

sys pat min lba asn ria [] system emp 下面就簡單來說一下spring boot 與mybatiis的整合問題,如果你還沒學習spring boot的註解的話,要先去看spring boot的註解 好了,現在讓我們來搞一下與mybat

Spring Boot學習進階筆記-添加定時任務

imp 配置 ren 時間 report rate enable lin enables 一、在Spring [email protected]/* */,啟用定時任務的配置。@SpringBootApplication@EnableSchedulingpubl

小白學習Code First

文件中 build 默認 dbm pcre student 技術分享 使用 類名 Code First約定: 註:EDMX模板 (SSDL:存儲模型=>數據庫表 ,CSDL:概念模型=>實體,C-S模型=>存儲和概念模型之間的映射關系) System.Da

Spring Boot幹貨系列:配置文件解析

set test profile ava java prefix 標註 了解 pre Spring Boot:配置文件解析 前言 上一篇介紹了Spring Boot的入門,知道了Spring Boot使用“習慣優於配置”(項目中存在大量的配置,此外

輕松入門機器學習概念總結

消息 目的 作者 固定 erp 效率 dev 常用 度量 歡迎大家前往雲加社區,獲取更多騰訊海量技術實踐幹貨哦~ 作者:許敏 接上篇:機器學習概念總結筆記(一) 8)邏輯回歸 logistic回歸又稱logistic回歸分析,是一種廣義的線性回歸分析模型,常用於數據挖掘

JavaWeb學習Hibernate框架

utils xtend auto etl SQ dial begin 可選 oct hibernateAPI詳解 Configuration 創建 加載主配置 創建sessionFactory

28 Java學習NIO Buffer(待補充

客戶 oca opened output write 系統方面 eba 了解 取出 一. Buffer介紹 Buffer,故名思意,緩沖區,實際上是一個容器,是一個連續數組。Channel提供從文件、網絡讀取數據的渠道,但是讀取或寫入的數據都必須經由Buffer。具體看下面

機器學習決策樹

天氣 次數 format 定義 表示 葉子節點 ast 代碼 wid 一、復習信息熵   為了解決特征選擇問題,找出最優特征,先要介紹一些信息論裏面的概念。   1、熵(entropy)          python3代碼實現: def calcShannonEnt(

28 Java學習NIO Buffer(待補充

一. Buffer介紹 Buffer,故名思意,緩衝區,實際上是一個容器,是一個連續陣列。Channel提供從檔案、網路讀取資料的渠道,但是讀取或寫入的資料都必須經由Buffer。具體看下面這張圖就理解了:   上面的圖描述了從一個客戶端向服務端傳送資料,然後服務端接收資料的過程。客戶端傳送資料時,必

系統學習機器學習特徵工程--離散型特徵編碼方式:LabelEncoder、one-hot與啞變數*

轉自:https://www.cnblogs.com/lianyingteng/p/7792693.html 在機器學習問題中,我們通過訓練資料集學習得到的其實就是一組模型的引數,然後通過學習得到的引數確定模型的表示,最後用這個模型再去進行我們後續的預測分類等工作。在模型訓練過程中,我們會對訓練

機器學習數學系列邏輯迴歸反向傳播數學推導

一、簡介   在深度學習領域,我們往往採用梯度下降(或上升)法來優化訓練函式模型,梯度下降法尤其是在優化凸函式上表現極佳。模型優化涉及到反向傳播過程,反向傳播過程需要先推匯出梯度計算公式然後利用機器進行代數運算。這篇博文的工作是詳細推導了邏輯迴歸反向傳播梯度計算公式(什麼是梯度?簡單來講

Spring Boot中使用WebSocket總結:向指定使用者傳送WebSocket訊息並處理對方不線上的情況

Spring Boot中使用WebSocket總結(二):向指定使用者傳送WebSocket訊息並處理對方不線上的情況 在上一篇文章(www.zifangsky.cn/1355.html)中我介紹了在Spring專案中使用WebSocket的幾種實現方式。但是,上篇文章中只介紹了服務端採用廣播模式給所有客戶