SpringBoot 启动及配置

1、SpringBoot 2.x 依赖环境和版本新特性说明

(1)依赖版本 JDK8 以上, SpringBoot 2.x 用 JDK8, 因为底层是 Spring Framework 5
(2)安装 maven 最新版本,maven 3.2 以上版本,下载地址 :https://maven.apache.org/download.cgi
(3)开发环境:Eclipse 或者 IDEA
(4)新特性

(5)翻译工具:https://translate.google.cn/
(6)SpringBoot GitHub 地址:https://github.com/spring-projects/spring-boot
(7)SpringBoot 官方文档:https://spring.io/guides/gs/spring-boot/

2、SpringBoot 之 HelloWorld 项目

## pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>net.xdclass</groupId>
  <artifactId>xdclass_springboot</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
  </parent>
  <dependencies>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
  </dependencies>
  
</project>
## SampleController.java

package net.xdclass.demo.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SampleController {

    @RequestMapping("/")
    String home() {
        return "Hello World!";
    }

    @RequestMapping("/test")
    public Map<String,String> testMap(){
    	Map<String,String> map = new HashMap<>();
    	map.put("name", "xdclass");
    	return map;
    }
}
## XdclassApplication

package net.xdclass.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;

//@SpringBootApplication 一个注解顶下面3个
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public class XdclassApplication {

	public static void main(String[] args) {
		SpringApplication.run(XdclassApplication.class, args);
	}
}
  • @RestController and @RequestMapping是SpringMVC的注解,不是SpringBoot特有的
  • @RestController = @Controller+@ResponseBody
  • @SpringBootApplication = @Configuration+@EnableAutoConfiguration+@ComponentScan
  • 访问地址:http://localhost:8080

3、HTTP GET、POST、PUT、DEL 请求

  • @GetMapping = @RequestMapping(method = RequestMethod.GET)
  • @PostMapping = @RequestMapping(method = RequestMethod.POST)
  • @PutMapping = @RequestMapping(method = RequestMethod.PUT)
  • @DeleteMapping = @RequestMapping(method = RequestMethod.DELETE)
## User.java

package net.xdclass.demo.domain;

public class User {

	private int age;
	
	private String pwd;
	
	private String phone;

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public User() {
		super();
	}

	public User(int age, String pwd, String phone) {
		super();
		this.age = age;
		this.pwd = pwd;
		this.phone = phone;
	}
}
## GetController.java

package net.xdclass.demo.controller;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import net.xdclass.demo.domain.User;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

//测试http协议的get请求
@RestController
public class GetController {
	private Map<String,Object> params = new HashMap<>();
	
	/**
	 * 功能描述:测试restful协议,从路径中获取字段
	 * @param cityId
	 * @param userId
	 * @return
	 */
	@RequestMapping(path = "/{city_id}/{user_id}", method = RequestMethod.GET)
	public Object findUser(@PathVariable("city_id") String cityId,
			@PathVariable("user_id") String userId ){
		params.clear();
		params.put("cityId", cityId);
		params.put("userId", userId);
		return params;
	}
	
	/**
	 * 功能描述:测试GetMapping
	 * @param from
	 * @param size
	 * @return
	 */
	@GetMapping(value="/v1/page_user1")
	public Object pageUser(int  from, int size ){
		params.clear();
		params.put("from", from);
		params.put("size", size);	
		return params;
	}
	
	/**
	 * 功能描述:默认值,是否必须的参数
	 * @param from
	 * @param size
	 * @return
	 */
	@GetMapping(value="/v1/page_user2")
	public Object pageUserV2(@RequestParam(defaultValue="0",name="page") int  from, int size ){
		
		params.clear();
		params.put("from", from);
		params.put("size", size);
		return params;
	}
	
	// @RequestParam(value = "name", required = true),required = true 表示必须有值的字段
	
	/**
	 * 功能描述:bean对象传参
	 * 注意:1、@RequestBody 请求体映射实体类
	 * 		2、注意需要指定http头 content-type 为 application/json  charset=utf-8
	 * 		3、使用body传输数据
	 * @param user
	 * @return
	 */
	@RequestMapping("/v1/save_user")
	public Object saveUser(@RequestBody User user){
		params.clear();
		params.put("user", user);
		return params;	
	}
	
	/**
	 * 功能描述:测试获取http头信息
	 * @RequestHeader 请求头,比如鉴权
	 * @param accessToken
	 * @param id
	 * @return
	 */
	@GetMapping("/v1/get_header")
	public Object getHeader(@RequestHeader("access_token") String accessToken, String id){
		params.clear();
		params.put("access_token", accessToken);
		params.put("id", id);
		return params;	
	}
	
	/**
	 * request 自动注入获取参数
	 * @param request
	 * @return
	 */
	@GetMapping("/v1/test_request")
	public Object testRequest(HttpServletRequest request){
		params.clear();
		String id = request.getParameter("id");
		params.put("id", id);
		return params;	
	}
}
## OtherHttpController.java

package net.xdclass.demo.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RestController;

// 测试 HTTP 协议的 post,del,put请求
@RestController
public class OtherHttpController {

	private Map<String,Object> params = new HashMap<>();
	
	/**
	 * 功能描述:测试PostMapping
	 * @param accessToken
	 * @param id
	 * @return
	 */
	@PostMapping("/v1/login")
	public Object login(String id, String pwd){
		params.clear();
		params.put("id", id);
		params.put("pwd", pwd);
		return params;	
	}
	
	@PutMapping("/v1/put")
	public Object put(String id){
		params.clear();
		params.put("id", id);
		return params;	
	}
	
	@DeleteMapping("/v1/del")
	public Object del(String id){
		params.clear();
		params.put("id", id);
		return params;	
	}
}

4、常用 JSON 框架及 Jackson 返回结果处理

(1)常用 JSON 框架
JSON 框架将JavaBean序列化为JSON,常用 JSON 框架有:SpringBoot 自带 Jackson 框架,阿里 FastJson,谷歌 Gson。性能:Jackson > FastJson > Gson > Json-lib。
Jackson、FastJson、Gson 类库各有优点,各有自己的专长。主要区别是用空间换时间,还是用时间换空间。
(2)Jackson 自定义返回 JSON 结构和格式

## pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>net.xdclass</groupId>
  <artifactId>xdclass_springboot</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
  </parent>

  <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  </dependencies>
</project>
## User.java

package net.xdclass.demo.domain;

import java.util.Date;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;

public class User {

	private int age;
	
	@JsonIgnore							// 指定字段不返回
	private String pwd;
	
	@JsonProperty("account")			// 指定别名
	@JsonInclude(Include.NON_NULL)		// 空字段不返回
	private String phone;
	
	// 指定日期格式
	@JsonFormat(pattern="yyyy-MM-dd hh:mm:ss",locale="zh",timezone="GMT+8")
	private Date createTime;

	public Date getCreateTime() {
		return createTime;
	}

	public void setCreateTime(Date createTime) {
		this.createTime = createTime;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public User() {
		super();
	}

	public User(int age, String pwd, String phone, Date createTime) {
		super();
		this.age = age;
		this.pwd = pwd;
		
		this.createTime = createTime;
	}
}
## JsonUtils.java

package net.xdclass.base_project.utils;

import java.io.IOException;

import org.springframework.util.StringUtils;

import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonUtils {
    private static ObjectMapper objectMapper = new ObjectMapper();
    
    //对象转字符串
    public static <T> String obj2String(T obj){
        if (obj == null){
            return null;
        }
        try {
            return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    //字符串转对象
    public static <T> T string2Obj(String str,Class<T> clazz){
        if (StringUtils.isEmpty(str) || clazz == null){
            return null;
        }
        try {
            return clazz.equals(String.class)? (T) str :objectMapper.readValue(str,clazz);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}
## JsonData.java

package net.xdclass.base_project.domain;

import java.io.Serializable;

/**
 * 功能描述:响应结果类
 */
public class JsonData implements Serializable {

	private static final long serialVersionUID = 1L;

	private Integer code; 		// 状态码 0 表示成功,1表示处理中,-1表示失败
	private Object data; 		// 数据
	private String msg;			// 描述

	public JsonData() {}

	public JsonData(Integer code, Object data, String msg) {
		this.code = code;
		this.data = data;
		this.msg = msg;
	}

	// 成功,传入数据
	public static JsonData buildSuccess() {
		return new JsonData(0, null, null);
	}

	// 成功,传入数据
	public static JsonData buildSuccess(Object data) {
		return new JsonData(0, data, null);
	}

	// 失败,传入描述信息
	public static JsonData buildError(String msg) {
		return new JsonData(-1, null, msg);
	}

	// 失败,传入描述信息,状态码
	public static JsonData buildError(String msg, Integer code) {
		return new JsonData(code, null, msg);
	}

	// 成功,传入数据,及描述信息
	public static JsonData buildSuccess(Object data, String msg) {
		return new JsonData(0, data, msg);
	}

	// 成功,传入数据,及状态码
	public static JsonData buildSuccess(Object data, int code) {
		return new JsonData(code, data, null);
	}

	public Integer getCode() {
		return code;
	}

	public void setCode(Integer code) {
		this.code = code;
	}

	public Object getData() {
		return data;
	}

	public void setData(Object data) {
		this.data = data;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	@Override
	public String toString() {
		return "JsonData [code=" + code + ", data=" + data + ", msg=" + msg
				+ "]";
	}
}
## SampleController.java

package net.xdclass.demo.controller;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import net.xdclass.demo.domain.User;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SampleController {

    @RequestMapping("/")
    String home() {
        return "Hello World!";
    }

    @RequestMapping("/test")
    public Map<String,String> testMap(){
    	Map<String,String> map = new HashMap<>();
    	map.put("name", "xdclass");
    	return map;
    }
    
    @GetMapping("/testjson")
    public Object testjson(){
    	return new User(111, "abc123", "10001000", new Date());
    }
}

5、SpringBoot 2.x 目录文件结构

  • src/main/java:存放后端代码
  • src/main/resources:
  • src/main/resources/static:存放 css、js、image 等静态文件(访问方式 http://localhost:8080/js/abc.js)
  • src/main/resources/templates:存放 jsp,html,tpl 等静态页面
  • src/main/resources/config:存放 application.properties 等配置文件

同名静态资源文件的加载顺序:SpringBoot 默认会依次从 resources/resources > resources/static > resources/public 里面找是否存在相应的资源,如果有则直接返回。
可以在配置文件 application.properties 中配置 SpringBoot 查找静态资源的路径,使得静态资源文件存放在其他路径也可以在浏览器中直接访问:

## application.properties

web.upload-path=/Users/jack/Desktop
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,classpath:/test/,file:${web.upload-path}

如果不做上述配置,则需要引入模板引擎 thymeleaf,否则 HTML 文件应该放在默认加载的文件夹里面,比如 resources、static、public 这几个文件夹,才可以访问。
引入 thymeleaf 模板引擎,在 pom.xml 中加入以下依赖:

## pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>net.xdclass</groupId>
  <artifactId>xdclass_springboot</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
  </parent>

  <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-thymeleaf</artifactId>
	</dependency>  
  </dependencies>
</project>

在生产中,静态资源文件一般存储在 CDN 中。

6、SpringBoot 2.x 实现文件上传

## upload.html

<!DOCTYPE html>
<html>
  <head>
    <title>uploadimg.html</title>
    <meta name="keywords" content="keyword1,keyword2,keyword3"></meta>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script src="/js/test.js" type="text/javascript"></script>
  </head>

  <body>
	  <form enctype="multipart/form-data" method="post" action="/upload">
	    文件:<input type="file" name="head_img"/>
	    姓名:<input type="text" name="name"/>
	    <input type="submit" value="上传"/>
	   </form>
  </body>
</html>
## pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>net.xdclass</groupId>
  <artifactId>xdclass_springboot</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
  </parent>

  <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>    
    <dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-thymeleaf</artifactId>
	</dependency>  
  </dependencies>
  <!-- 打包成jar包,需要增加maven依赖 -->
  <build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
	</plugins>
  </build>
  <!-- 如果没加相关依赖,执行maven打包,运行后会报错:no main manifest attribute, in XXX.jar -->
  <!-- GUI:反编译工具,作用就是用于把class文件转换成java文件 -->
</project>
## application.properties

# 文件上传和访问需要指定磁盘路径
web.upload-path=/Users/jack/Desktop
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,classpath:/test/,file:${web.upload-path} 
## JsonData.java

package net.xdclass.demo.domain;

import java.io.Serializable;

public class JsonData implements Serializable {
	private static final long serialVersionUID = 1L;

	//状态码,0表示成功,-1表示失败
	private int code;
	
	//结果
	private Object data;

	//错误描述
	private String msg;
	
	public int getCode() {
		return code;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	public void setCode(int code) {
		this.code = code;
	}

	public Object getData() {
		return data;
	}

	public void setData(Object data) {
		this.data = data;
	}

	public JsonData(int code, Object data) {
		super();
		this.code = code;
		this.data = data;
	}

	public JsonData(int code, String msg,Object data) {
		super();
		this.code = code;
		this.msg = msg;
		this.data = data;
	}
}
## FileController.java

package net.xdclass.demo.controller;

import java.io.File;
import java.io.IOException;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import net.xdclass.demo.domain.JsonData;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

/**
 * 功能描述:文件测试
 */
@Controller
public class FileController {
	@RequestMapping(value = "/api/v1/gopage")  
	public Object index() {
		return "index";
	}

   	private static final String filePath = "/Users/jack/Desktop/person/springboot/xdclass_springboot/src/main/resources/static/images/";  

 	@RequestMapping(value = "upload")
    @ResponseBody
    public JsonData upload(@RequestParam("head_img") MultipartFile file,HttpServletRequest request) {
      
 		//file.isEmpty(); 判断图片是否为空
 		//file.getSize(); 图片大小进行判断
 		
 		String name = request.getParameter("name");
 		System.out.println("用户名:"+name);
        
 		// 获取文件名
        String fileName = file.getOriginalFilename();	        
        System.out.println("上传的文件名为:" + fileName);
        
        // 获取文件的后缀名,比如图片的jpeg,png
        String suffixName = fileName.substring(fileName.lastIndexOf("."));
        System.out.println("上传的后缀名为:" + suffixName);
        
        // 文件上传后的路径
        fileName = UUID.randomUUID() + suffixName;
        System.out.println("转换后的名称:"+fileName);
        
        File dest = new File(filePath + fileName);
       
        try {
        	// MultipartFile 对象的 transferTo 方法,用于文件保存,效率和操作比原先用 FileOutStream 方便和高效
            file.transferTo(dest);            
            return new JsonData(0, fileName);
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return  new JsonData(-1, "fail to save ", null);
    }	
}
## XdclassApplication.java

package net.xdclass.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;

//@SpringBootApplication 一个注解顶下面3个
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public class XdclassApplication {

	// 文件大小配置,启动类里面配置
	@Bean  
    public MultipartConfigElement multipartConfigElement() {  
        MultipartConfigFactory factory = new MultipartConfigFactory();  
        // 单个文件最大  
        factory.setMaxFileSize("10240KB"); //KB,MB  
        /// 设置总上传数据总大小  
        factory.setMaxRequestSize("1024000KB");  
        return factory.createMultipartConfig();  
    }
		    
	public static void main(String[] args) {
		SpringApplication.run(XdclassApplication.class, args);
	}
}

常见的文件服务器有:FastDFS,阿里云OSS,可以自己用 Nginx 搭建一个简单的文件服务器。

7、SpringBoot 2.x 使用 Dev-tool 热部署

  • 使用 SpringBoot 结合 Dev-tool 工具,快速加载启动应用。
  • 官方地址:https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/reference/htmlsingle/#using-boot-devtools
  • 在 pom.xml 中添加核心依赖包:
<dependency>  
     <groupId>org.springframework.boot</groupId>  
     <artifactId>spring-boot-devtools</artifactId>  
     <optional>true</optional>  
 </dependency>
  • 添加依赖后,在 IDEA 里面重启应用,后续修改后热部署马上可以生效。
    默认不被热部署的文件:/META-INF/maven,/META-INF/resources,/resources,/static,/public,/templates
  • 指定文件不进行热部署:
spring.devtools.restart.exclude=static/**,public/**
  • 手工触发重启:
spring.devtools.restart.trigger-file=trigger.txt

改代码不重启,通过一个文本去控制。
注意:生产环境不要开启这个功能,如果用java -jar启动,SpringBoot是不会进行热部署的。

8、配置文件

常见的配置文件有:xml、properties、json、yaml。
YAML(Yet Another Markup Language),写 YAML 要比写 XML 快得多,无需关注标签或引号,使用空格 Space 缩进表示分层,不同层次之间的缩进可以使用不同的空格数目。注意:key 的冒号后面一定要跟一个空格,形成树状结构。

  • application.properties 示例:
server.port=8090  
server.session-timeout=30  
server.tomcat.max-threads=0  
server.tomcat.uri-encoding=UTF-8 
  • application.yml 示例:
server:  
	port: 8090  
	session-timeout: 30  
	tomcat.max-threads: 0  
	tomcat.uri-encoding: UTF-8

9、使用注解将配置文件自动映射到属性和实体类

(1)方式一

  • Controller 上面配置:
@Controller
@PropertySource({"classpath:application.properties"})
public class FileController {
}
  • 增加属性:
@Value("${web.file.path}")
private String filePath;

(2)方式二:实体类配置文件

  • 添加 @Component 注解
  • 使用 @PropertySource 注解指定配置文件位置
  • 使用 @ConfigurationProperties 注解,设置相关属性
  • 必须通过注入 IOC 对象 Resource 进来, 才能在类中使用获取的配置文件值
## ServerSettings.java

package net.xdclass.demo.domain;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

//服务器配置
@Component
@PropertySource({"classpath:application.properties"})
//@ConfigurationProperties(prefix="test")
@ConfigurationProperties

public class ServerSettings {

	//名称
	//@Value("${appname}")
	private String name;
	
	//@Value("${domain}")
	private String domain;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getDomain() {
		return domain;
	}

	public void setDomain(String domain) {
		this.domain = domain;
	}
}
## GetController.java

	@Autowired
	private ServerSettings serverSettings;
	
	@GetMapping("/v1/test_properties")
	public Object testPeroperties(){
		return serverSettings;	
	}
## application.properties

web.upload-path=/Users/jack/Desktop
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,classpath:/test/,file:${web.upload-path}

#指定某些文件不进行监听,即不会进行热加载
#spring.devtools.restart.exclude=application.properties

#通过触发器,去控制什么时候进行热加载部署新的文件
spring.devtools.restart.trigger-file=trigger.txt

server.port=8081

#文件上传路径配置
web.file.path=/Users/jack/Desktop/

#测试配置文件注入
test.domain=www.xdclass.net
test.name=springboot
## trigger.txt

version=8
## pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>net.xdclass</groupId>
  <artifactId>xdclass_springboot</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
  </parent>

  <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>        
    <dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-devtools</artifactId>
		<optional>true</optional>
	</dependency>
  </dependencies>

  <build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
	</plugins>
  </build>
</project>

常见问题:
(1)配置文件注入失败,报错:Could not resolve placeholder
解决方案:根据 SpringBoot 启动流程,有些注解自动扫描包并没有扫描到,是因为默认 Spring 框架实现会从声明 @ComponentScan 所在的类的 package 进行扫描,来自动注入,因此启动类最好放在根路径下面,或者指定扫描包范围,启动类添加了 @ComponentScan 后,SpringBoot 扫描启动类对应的目录和子目录。
(2)注入bean的方式,属性名称和配置文件里面的 key 如果一一对应,就只加@Value 这个注解,如果不一样,就要加 @value("${XXX}") 注解。

10、单元测试

(1)SpringBootTest

## pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>net.xdclass</groupId>
	<artifactId>xdclass_springboot</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.1.RELEASE</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional>
		</dependency>
		<!-- springboot程序测试依赖,如果是自动创建项目默认添加 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>
## SpringBootTestDemo

package xdclass_springboot.demo;

import junit.framework.TestCase;
import net.xdclass.demo.XdclassApplication;

import org.junit.After;
import org.junit.Before;
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)  							// 底层用junit  SpringJUnit4ClassRunner
@SpringBootTest(classes={XdclassApplication.class})		// 启动整个springboot工程
public class SpringBootTestDemo {
	@Test
	public void testOne(){
		System.out.println("test hello 1");
		TestCase.assertEquals(1, 1);
	}
	
	@Test
	public void testTwo(){
		System.out.println("test hello 2");
		TestCase.assertEquals(1, 1);
	}
	
	@Before
	public void testBefore(){
		System.out.println("before");
	}
	
	@After
	public void testAfter(){
		System.out.println("after");
	}
}

(2)MockMvc 模拟 HTTP 请求进行 Controller 层测试

## MockMvcTestDemo.java

package xdclass_springboot.demo;

import net.xdclass.demo.XdclassApplication;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

/**
 * 功能描述:测试mockmvc类
 */
@RunWith(SpringRunner.class)  							// 底层用junit  SpringJUnit4ClassRunner
@SpringBootTest(classes={XdclassApplication.class}) 	// 启动整个springboot工程
@AutoConfigureMockMvc 
public class MockMvcTestDemo {
	@Autowired
	private MockMvc mockMvc;
	
	@Test
	public void apiTest() throws Exception {
		MvcResult mvcResult =  mockMvc
			// 执行一个 RequestBuilder 请求
			.perform( MockMvcRequestBuilders.get("/test/home_xxx"))
			// 添加 ResultMatcher -> MockMvcResultMatchers 验证规则
			.andExpect( MockMvcResultMatchers
			.status()
			.isOk())
			// 最后返回相应的 MvcResult -> Response
			.andReturn();
		int status = mvcResult.getResponse().getStatus();
		System.out.println(status);
	}
}

11、个性化启动 banner 设置

修改 SpringBoot 启动的 banner 信息:
(1)在类路径下增加一个 banner.txt,里面是启动要输出的信息

## banner.txt

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )----☺ ☺ ☺ ☺ ☺ ☺ ☺ ☺ ☺
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: yanyan.blog.csdn.net SpringBoot2.x ::        (v2.0.1.RELEASE)

(2)在 applicatoin.properties 增加 banner 文件的路径地址

spring.banner.location=banner.txt

12、全局异常配置

(1)输出 debug 日志

> java -jar xxx.jar --debug

(2)抛出异常

## ExcptionController.java

package net.xdclass.demo.controller;

import java.util.Date;

import net.xdclass.demo.domain.User;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 功能描述:异常测试
 */
@RestController
public class ExcptionController {
	@RequestMapping(value = "/api/v1/test_ext")  
	public Object index() {
		int i= 1/0;
		return new User(11, "sfsfds", "1000000", new Date());
	}
}

(3)全局异常处理器

## CustomExtHandler.java

package net.xdclass.demo.domain;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

// @ControllerAdvice,异常注解,如果是返回 JSON 数据,则用 RestControllerAdvice,就可以不加 @ResponseBody
@RestControllerAdvice
public class CustomExtHandler {
    private static final Logger LOG = LoggerFactory.getLogger(CustomExtHandler.class);

	//捕获全局异常,处理所有不可知的异常
	@ExceptionHandler(value=Exception.class)
	//@ResponseBody
    Object handleException(Exception e,HttpServletRequest request){
		LOG.error("url {}, msg {}",request.getRequestURL(), e.getMessage()); 
		Map<String, Object> map = new HashMap<>();
	        map.put("code", 100);
	        map.put("msg", e.getMessage());
	        map.put("url", request.getRequestURL());
	        return map;
    }
}

(4)自定义异常
自定义异常:

## MyException.java

package net.xdclass.demo.domain;

/**
 * 功能描述:自定义异常类
 */
public class MyException extends RuntimeException {
	private String code;
    private String msg;
    
    public MyException(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

	public String getCode() {
		return code;
	}
	public void setCode(String code) {
		this.code = code;
	}
	public String getMsg() {
		return msg;
	}
	public void setMsg(String msg) {
		this.msg = msg;
	}
}

抛出自定义异常:

## ExceptionController.java

package net.xdclass.demo.controller;

import java.util.Date;

import net.xdclass.demo.domain.MyException;
import net.xdclass.demo.domain.User;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 功能描述:异常测试
 */
@RestController
public class ExcptionController {
	/**
	 * 功能描述:模拟全局异常
	 * @return
	 */
	@RequestMapping(value = "/api/v1/test_ext")  
	public Object index() {
		int i= 1/0;
		return new User(11, "sfsfds", "1000000", new Date());
	}
	
	/**
	 * 功能描述:模拟自定义异常
	 * @return
	 */
	@RequestMapping("/api/v1/myext")
	public Object myexc(){
		throw new MyException("499", "my ext异常");
	}
}

处理自定义异常:

## CustomExtHandler.java

package net.xdclass.demo.domain;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;

@RestControllerAdvice
public class CustomExtHandler {
    private static final Logger LOG = LoggerFactory.getLogger(CustomExtHandler.class);
	
	// 捕获全局异常,处理所有不可知的异常
	@ExceptionHandler(value=Exception.class)
    Object handleException(Exception e,HttpServletRequest request){
		LOG.error("url {}, msg {}",request.getRequestURL(), e.getMessage()); 
		Map<String, Object> map = new HashMap<>();
	        map.put("code", 100);
	        map.put("msg", e.getMessage());
	        map.put("url", request.getRequestURL());
	        return map;
    }

	/**
	 * 功能描述:处理自定义异常
	 * @return
	 */
	@ExceptionHandler(value=MyException.class)
    Object handleMyException(MyException e,HttpServletRequest request){
		// 进行页面跳转
		// ModelAndView modelAndView = new ModelAndView();
		// modelAndView.setViewName("error.html");
		// modelAndView.addObject("msg", e.getMessage());
		// return modelAndView;
		
		// 返回json数据,由前端去判断加载什么页面
		Map<String, Object> map = new HashMap<>();
        map.put("code", e.getCode());
        map.put("msg", e.getMsg());
        map.put("url", request.getRequestURL());
        return map;
    }
}

异常页面:

## error.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Insert title here</title>
	</head>
	<body>
		出异常啦 template
		<h1>xdclass.net</h1>
	</body>
</html>

返回自定义异常界面,需要引入 thymeleaf 依赖:

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

13、SpringBoot 启动方式

(1)SpringBoot Jar 包方式启动
在 pom.xml 中添加 maven 插件:

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
	</plugins>
</build>

jar 包方式启动:

> java -jar spring-boot-demo-0.0.1-SNAPSHOT.jar

如果没有添加上述 maven 插件,报错:no main manifest attribute, in spring-boot-demo-0.0.1-SNAPSHOT.jar。
如果部署环境已安装 maven,可以使用以下命令启动 SpringBoot:

> mvn spring-boot:run

jar 包目录结构如下:

example.jar
	 |
	 +-META-INF
	 |  +-MANIFEST.MF
	 +-org
	 |  +-springframework
	 |     +-boot
	 |        +-loader
	 |           +-<spring boot loader classes>
	 +-BOOT-INF
	    +-classes
	    |  +-mycompany
	    |     +-project
	    |        +-YourClasses.class
	    +-lib
	       +-dependency1.jar
	       +-dependency2.jar

(2)SpringBoot War 包方式启动
修改 pom.xml 文件如下:

## pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>net.xdclass</groupId>
  <artifactId>base_project</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <!-- 打包方式,将打包形式由jar修改为war -->
  <packaging>war</packaging>
	 <parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.1.RELEASE</version>
	 </parent>
 
	 <properties>
	 </properties>
 
 	 <dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
	<!-- 打包的项目名称 -->
	<finalName>xdclass_springboot</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

修改启动类:

## XdclassApplication.java

package net.xdclass.base_project;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class XdclassApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(XdclassApplication.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(XdclassApplication.class, args);
    }
}

(3)性能测试工具
Jmeter 测试工具可用于测试性能,如 QPS,TPS,RT。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页