Spring Boot使開發獨立的,產品級別的基於Spring的應用變得很是簡單,你只需"just run"。 咱們爲Spring平臺及第三方庫提供開箱即用的設置,這樣你就能夠有條不紊地開始。多數Spring Boot應用須要不多的Spring配置。css
你可使用Spring Boot建立Java應用,並使用java -jar啓動它或採用傳統的war部署方式。html
l 依賴太多了, 且存在版本問題前端
l 配置太多了且每次都同樣, 大部分工程, 配置每次都是同樣的, 從一個地方拷貝到另一個地方. 且Spring發展10多年, 各類配置版本太多, 對於不少程序員來講, 分不清哪一個是有效, 哪一個無效.java
l 部署太麻煩. 須要tomcat部署, 項目結構也須要照着Java EE的目錄結構來寫.mysql
l 建立獨立的Spring應用程序程序員
l 嵌入的Tomcat,無需部署WAR文件web
l 簡化Maven配置redis
l 自動配置Springspring
l 提供生產就緒型功能,如指標,健康檢查和外部配置sql
l 絕對沒有代碼生成和對XML沒有要求配置
l 自動配置(auto-configuration)
一項簡化配置的功能,好比在classpath中發現有spring security的jar包,則自動建立相關的bean等
l starters(簡化依賴)
這個比較關鍵,方便spring去集成各種組件,好比redis、mongodb等等。
默認狀況下,本堂課使用SpringBoot 2.1.2最新版本,最好安裝JDK8以及以上的版本,maven使用3.3或者以上的版本(本教程使用maven3.6版本)
新建一個普通maven項目
建立pom文件
<?xml version="1.0" encoding="UTF-8"?>
<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>enjoy</groupId>
<artifactId>springbootvip</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
編寫代碼:
爲了完成應用程序,咱們須要建立一個單獨的Java文件。Maven默認會編譯src/main/java下的源碼
新建:cn.enjoy.Example
package cn.enjoy;
import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;
@RestController
@EnableAutoConfiguration
public class Example {
@RequestMapping("/")
String home() {
return "Hello World!";
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Example.class, args);
}
}
@RestController和@RequestMapping說明:
@RestController。這被稱爲一個構造型(stereotype)註解。它爲閱讀代碼的人們提供建議。對於Spring,該類扮演了一個特殊角色。在本示例中,咱們的類是一個web @Controller,因此當處理進來的web請求時,Spring會詢問它。
@RequestMapping註解提供路由信息。它告訴Spring任何來自"/"路徑的HTTP請求都應該被映射到home方法。@RestController註解告訴Spring以字符串的形式渲染結果,並直接返回給調用者。
@EnableAutoConfiguration。這個註解告訴Spring Boot根據添加的jar依賴猜想你想如何配置Spring。因爲spring-boot-starter-web添加了Tomcat和Spring MVC,因此auto-configuration將假定你正在開發一個web應用並相應地對Spring進行設置。
main方法。這只是一個標準的方法,它遵循Java對於一個應用程序入口點的約定。咱們的main方法經過調用run,將業務委託給了Spring Boot的SpringApplication類。SpringApplication將引導咱們的應用,啓動Spring,相應地啓動被自動配置的Tomcat web服務器。咱們須要將Example.class做爲參數傳遞給run方法來告訴SpringApplication誰是主要的Spring組件。
執行main方法,使用一個瀏覽器打開 localhost:8080,如下輸出:
Hello World!
Spring Boot不須要使用任何特殊的代碼結構,然而,這裏有一些地方須要注意
使用"default"包
當類沒有包含package聲明時,它被認爲處於default package下。一般不推薦使用default package,並應該避免使用它。由於對於使用@ComponentScan,@EntityScan或@SpringBootApplication註解的Spring Boot應用來講,來自每一個jar的類都會被讀取,這會形成必定的問題。
定位main應用類
一般建議你將main應用類放在位於其餘類上面的根包(root package)中。一般使用@EnableAutoConfiguration註解你的main類,而且暗地裏爲某些項定義了一個基礎「search package」。例如,若是你正在編寫一個JPA應用,被@EnableAutoConfiguration註解的類所在包將被用來搜索@Entity項。
使用根包容許你使用@ComponentScan註解而不須要定義一個basePackage屬性。若是main類位於根包中,你也可使用@SpringBootApplication註解。
下面是一個典型的結構:
cn
+- enjoy
+- myproject
+- Application.java
|
+- domain
| +- Customer.java
| +- CustomerRepository.java
|
+- service
| +- CustomerService.java
|
+- web
+- CustomerController.java
能夠繼承spring-boot-starter-parent項目來獲取合適的默認設置。
想配置你的項目繼承spring-boot-starter-parent只須要簡單地設置parent爲:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
</parent>
注:你應該只須要在該依賴上指定Spring Boot版本。若是導入其餘的starters,你能夠放心的省略版本號。
使用沒有父POM的Spring Boot
不是每一個人都喜歡繼承spring-boot-starter-parent POM。你可能須要使用公司標準parent,或你可能傾向於顯式聲明全部Maven配置。
若是你不使用spring-boot-starter-parent,經過使用一個scope=import的依賴,你仍能獲取到依賴管理的好處:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
登錄\註冊
CREATE TABLE `enjoy_user` (
`id` int NOT NULL AUTO_INCREMENT ,
`passwd` varchar(255) NULL ,
`username` varchar(255) NULL ,
PRIMARY KEY (`id`)
);
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
新建App.java
@SpringBootApplication
public class App {
public static void main(String[] args) throws Exception {
SpringApplication.run(App.class, args);
}
}
package cn.enjoy.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@RequestMapping("/hello")
public Object sayHello() {
return "hello";
}
}
運行App,在瀏覽器輸入:localhost:8080/hello,發現「hello」說明第一步部署成功。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
在resources目錄,新建application.properties文件,增長內容以下
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/spring?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root1234%
mybatis.mapperLocations=classpath:mapping/*.xml
準備mybatis的生成文件generatorConfig.xml,並在相應目錄建立好model,dao,mapping文件夾
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- 數據庫驅動:選擇你的本地硬盤上面的數據庫驅動包-->
<classPathEntry location="C:\Users\VULCAN\.m2\repository\mysql\mysql-connector-java\5.1.37\mysql-connector-java-5.1.37.jar"/>
<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressDate" value="true"/>
<!-- 是否去除自動生成的註釋 true:是 : false:否 -->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--數據庫連接URL,用戶名、密碼 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1:3306/spring" userId="root" password="root1234%">
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 生成模型的包名和位置-->
<javaModelGenerator targetPackage="cn.enjoy.model" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成映射文件的包名和位置-->
<sqlMapGenerator targetPackage="mapping" targetProject="src/main/resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 生成DAO的包名和位置-->
<javaClientGenerator type="XMLMAPPER" targetPackage="cn.enjoy.dao" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 要生成的表 tableName是數據庫中的表名或視圖名 domainObjectName是實體類名-->
<table tableName="enjoy_user" domainObjectName="Users" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
</context>
</generatorConfiguration>
右鍵生成:結構圖以下
注意:得再App啓動類上增長@MapperScan掃描註解
@SpringBootApplication
@MapperScan("cn.enjoy.dao")
public class App {
public static void main(String[] args) throws Exception {
SpringApplication.run(App.class, args);
}
}
Users findByUsernameAndPasswd(@Param("username") String username, @Param("passwd") String passwd);
對應的XML配置
<select id="findByUsernameAndPasswd" resultType="cn.enjoy.model.Users" parameterType="map">
select
<include refid="Base_Column_List" />
from enjoy_user where 1=1
<if test="passwd != null" >
and passwd = #{passwd,jdbcType=VARCHAR}
</if>
<if test="username != null" >
and username = #{username,jdbcType=VARCHAR}
</if>
limit 1
</select>
要測試剛纔新增的Mapper方法是否成功,這裏須要單元測試,在springboot中是有專門的組件來作單元測試的,在pom文件中新增依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
新建UserTest放置在test目錄下
package cn.enjoy.test;
import cn.enjoy.App;
import cn.enjoy.dao.UsersMapper;
import cn.enjoy.model.Users;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
@SpringBootTest(classes = {App.class})
@RunWith(SpringRunner.class)
public class UserTest {
@Resource
private UsersMapper usersMapper;
@Test
public void testAdd() {
Users user = new Users() ;
user.setPasswd("123");
user.setUsername("enjoy");
usersMapper.insertSelective(user);
}
@Test
public void testFindUser() {
Users enjoy = usersMapper.findByUsernameAndPasswd("enjoy", "123");
System.out.println(enjoy);
}
}
這樣SpringBoot集成單元測試成功!
新增接口IUserService
public interface IUserService {
boolean login(String username,String passwd);
boolean register(String username,String passwd);
}
建立實現類
package cn.enjoy.service.impl;
import cn.enjoy.dao.UsersMapper;
import cn.enjoy.model.Users;
import cn.enjoy.service.IUserService;
import javax.annotation.Resource;
@Service
public class UserServiceImpl implements IUserService {
@Resource
private UsersMapper usersMapper;
@Override
public boolean login(String username, String passwd) {
Users users = usersMapper.findByUsernameAndPasswd(username, passwd);
return users != null;
}
@Override
public boolean register(String username, String passwd) {
Users users = new Users();
users.setUsername(username);
users.setPasswd(passwd);
int cnt = usersMapper.insertSelective(users);
return cnt > 0;
}
}
修改UserController,增長login和register方法
package cn.enjoy.controller;
import cn.enjoy.service.IUserService; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController public class UserController {
@Resource private IUserService iUserService;
@RequestMapping("/hello") public Object sayHello() { return "hello"; }
@RequestMapping("/login") public String login(String username,String passwd) { boolean login = iUserService.login(username, passwd); if(login) { return "登錄成功"; }else { return "登錄失敗"; } }
@RequestMapping("/register") public String register(String username,String passwd) { boolean login = iUserService.register(username, passwd); if(login) { return "註冊成功"; }else { return "註冊失敗"; } } }
|
在瀏覽器上輸入:localhost:8080/register?username=deer&passwd=123,顯示「註冊成功」
在瀏覽器上輸入:localhost:8080/login?username=deer&passwd=123,顯示「登錄成功」
修改IUserService接口,增長一個新增batchAdd方法,在UserServiceImpl增長相應實現類,在實現類中故意產生一個被0整除得異常
package cn.enjoy.service;
public interface IUserService {
boolean login(String username,String passwd);
boolean register(String username,String passwd);
void batchAdd(String username,String passwd);
}
package cn.enjoy.service.impl;
import cn.enjoy.dao.UsersMapper;
import cn.enjoy.model.Users;
import cn.enjoy.service.IUserService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class UserServiceImpl implements IUserService {
@Resource
private UsersMapper usersMapper;
@Override
public boolean login(String username, String passwd) {
Users users = usersMapper.findByUsernameAndPasswd(username, passwd);
return users != null;
}
@Override
public boolean register(String username, String passwd) {
Users users = new Users();
users.setUsername(username);
users.setPasswd(passwd);
int cnt = usersMapper.insertSelective(users);
return cnt > 0;
}
@Override
public void batchAdd(String username, String passwd) {
Users users = new Users();
users.setUsername(username);
users.setPasswd(passwd);
usersMapper.insertSelective(users);
int i = 10 /0;
users = new Users();
users.setUsername(username+"2");
users.setPasswd(passwd);
usersMapper.insertSelective(users);
}
}
修改UserContoller,增長batchAdd方法
@RequestMapping("/batchAdd")
public String batchAdd(String username,String passwd) {
iUserService.batchAdd(username, passwd);
return "成功";
}
從新運行,在瀏覽器上輸入:localhost:8080/batchAdd?username=enjoy&passwd=123
能夠發如今瀏覽器上出現
檢查數據庫,發現表裏面已經產生了一個錯誤的數據,產生了事務問題。
事務支持:
在batchAdd方法上增長@Transactional註解,重啓服務後,在瀏覽器上輸入
localhost:8080/batchAdd?username=enjoy&passwd=123
瀏覽器還繼續報錯,但檢查數據庫,事務問題已經獲得瞭解決
經過上面步驟,雖然已經解決了事務問題,但界面上出現這500錯誤,這對用戶來講仍是不友好。
通常在企業裏面對這些異常通常都會統一捕獲,由一個專門的異常處理類來統一處理。
package cn.enjoy.utils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
/**
* 異常處理類
*/
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = RuntimeException.class)
@ResponseBody
public Object defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
e.printStackTrace();
return "我是個異常處理類";
}
}
重啓服務後,在瀏覽器上輸入會出現異常的服務
localhost:8080/batchAdd?username=enjoy&passwd=123
界面返回:
在瀏覽器上故意輸錯地址
localhost:8080/batchAddx?username=enjoy&passwd=123,後端並無這服務,雖然已經作了相關的異常捕獲,但瀏覽器仍是顯示了。
這個時候就要作404(其餘異常代碼同樣)
在配置這樣錯誤頁面的時候,之前是在WEB.XML中進行配置,而在這裏,須要有個WebServerFactoryCustomizer的實例進行配置
在前面創建的GlobalExceptionHandler,新建一個方法
@Bean
public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer(){
return (factory->{
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/404.do");
factory.addErrorPages( error404Page);
});
}
新建BaseController
package cn.enjoy.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class BaseController {
@RequestMapping("/404.do")
public Object error_404() {
return "你要找的頁面,被lison偷吃了!";
}
}
重啓服務,在瀏覽器上輸入
localhost:8080/batchAddx?username=enjoy&passwd=123
此時,頁面返回「你要找的頁面,被lison偷吃了!」
注意:WebServerFactoryCustomizer這種配置方式是在SpringBoot2以後才這樣配置的,在1.X的版本須要用到的是EmbeddedServletContainerCustomizer
代碼以下
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return (container -> {
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/404.do");
container.addErrorPages( error404Page);
});
}
靜態資源:js, css, html, 圖片,音視頻等
靜態資源路徑:是指系統能夠直接訪問的路徑,且路徑下的全部文件都可被用戶直接讀取。
Spring Boot默認提供靜態資源目錄位置需置於classpath下,目錄名需符合以下規則:
/static
/public
/resources
/META-INF/resources
在resources目錄下面創建static文件夾,在文件夾裏面任意放張圖片。
命名爲:enjoy.jpg
在地址欄上輸入localhost:8080/enjoy.jpg,能夠看到圖片
通常來講springboot不建議直接使用jsp頁面,但不排除有些公司的項目依然使用jsp作前端界面。
springboot內置的tomcat並無集成對jsp的支持,也沒有對EL表達式的支持,所以要使用jsp應該先把相關的依賴集成進來
在pom文件裏面新增
<!--JavaServer Pages Standard Tag Library,JSP標準標籤庫-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!--內置tocat對Jsp支持的依賴,用於編譯Jsp-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
因爲要springmvc解析jsp,要配置試圖解析器,在applicaiton.properties 裏面新增
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
在resources裏面新建WEB-INF文件夾,在裏面放一個index.jsp頁面
內容以下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>享學課堂</title>
</head>
<body>
<h1>這是個jsp頁面!!</h1>
</body>
</html>
最後新建一個controller,注意這裏的註解是@Controller,千萬不能用@RestController
package cn.enjoy.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/jsp")
public class JspController {
@RequestMapping("/hi")
public String sayHello() {
return "index";
}
}
在瀏覽器上輸入:localhost:8080/jsp/hi,能夠看到JSP頁面。
SpringBoot 推薦使用模板引擎來渲染html,若是你不是歷史遺留項目,必定不要使用JSP,經常使用的模板引擎不少,有freemark,thymeleaf等,其實都大同小異
其中springboot 強烈推薦的是用thymeleaf
pom文件種添加thymeleaf的支持,而且刪除JSP的支持
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--<!–JavaServer Pages Standard Tag Library,JSP標準標籤庫–>-->
<!--<dependency>-->
<!--<groupId>javax.servlet</groupId>-->
<!--<artifactId>jstl</artifactId>-->
<!--</dependency>-->
<!--<!–內置tocat對Jsp支持的依賴,用於編譯Jsp–>-->
<!--<dependency>-->
<!--<groupId>org.apache.tomcat.embed</groupId>-->
<!--<artifactId>tomcat-embed-jasper</artifactId>-->
<!--</dependency>-->
刪除application.properties文件裏面視圖解析器內容
#spring.mvc.view.prefix=/WEB-INF/jsp/
#spring.mvc.view.suffix=.jsp
新建Controller內容以下
package cn.enjoy.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/tpl")
public class ThymeleafController {
@RequestMapping("/testThymeleaf")
public String testThymeleaf(ModelMap map) {
// 設置屬性
map.addAttribute("name", "enjoy");
// testThymeleaf:爲模板文件的名稱
// 對應src/main/resources/templates/testThymeleaf.html
return "testThymeleaf";
}
}
Springboot默認的模板配置路徑爲:src/main/resources/templates
在resources目錄裏面新建一個templates目錄,在目錄裏面新建testThymeleaf.html文件
<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head lang="en">
<meta charset="UTF-8" />
<title>enjoy</title>
</head>
<body>
<h1 th:text="${name}"/>
</body>
</html>
在瀏覽器上輸入:localhost:8080/tpl/testThymeleaf,能夠看到頁面。
Swagger2 的做用
l 隨項目自動生成強大RESTful API文檔,減小工做量
l API文檔與代碼整合在一塊兒,便於同步更新API說明
l 頁面測試功能來調試每一個RESTful API
修改pom文件,添加swagger2的相關依賴
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
新建一個swagger的配置類SwaggerConfig.java
package cn.enjoy.utils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
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 SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("cn.enjoy"))// 指定掃描包下面的註解
.paths(PathSelectors.any())
.build();
}
// 建立api的基本信息
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("集成Swagger2構建RESTful APIs")
.description("集成Swagger2構建RESTful APIs")
.termsOfServiceUrl("http://www.xiangxueketang.cn/")
.contact(new Contact("enjoy","cn.xiangxueketang","enjoy@enjoy.cn"))
.version("1.0.0")
.build();
}
}
新建Controller用於顯示相關接口
package cn.enjoy.controller;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping(value="/swagger")
public class SwaggerController {
@ApiOperation(value="獲取用戶信息", notes="根據id來獲取用戶詳細信息")
@ApiImplicitParam(name="id", value="用戶ID", required=true, dataType="String")
@RequestMapping(value="/{id}", method= RequestMethod.GET)
public Map<String,String> getInfo(@PathVariable String id) {
Map<String ,String> map = new HashMap<String, String>();
map.put("name", "lison");
map.put("age", "38");
return map;
}
}
訪問:http://localhost:8080/swagger-ui.html
java有許多的日誌組件,好比 log4j,log4j2,logback還有java自生提供的Java Util Logging,其實在springboot中對這些組件都提供了支持,log4j,log4j2和logback都提供相應的組件支持。
在springboot中默認使用的日誌工具是logback,不過在說起具體的日誌工具以前要提一個名詞,這個名詞就是slf4j(Simple Logging Facade For Java)
百度百科解釋
https://baike.baidu.com/item/slf4j/6408868
slf4j不是具體的日誌解決方案,它有點相似於jdbc,使用了門面模式,是一個針對各種日誌的抽象實現,既然是抽象的日誌實現,在springboot中確定不須要額外導入。
注意:spring-boot-starter中就提供了對spring-boot-starter-logging的依賴
在spring-boot-starter-logging中能夠看到以及集成了slf4j與具體實現logback的默認支持
修改UserController
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final Logger logger = LoggerFactory.getLogger(UserController.class);
在瀏覽器上輸入:localhost:8080/hello,能夠看控制檯日誌的輸出
修改controller 把日誌的輸出改爲
logger.debug("這個一個hello日誌");
這個時候重啓,再調用,發現後臺並不會有任何輸出,這緣由是日誌級別在做祟
默認狀況下,Spring Boot 配置的是INFO 日誌級別,也就是會輸出INFO級別以上的日誌(ERROR, WARN, INFO)。
若是須要 Debug 級別的日誌。在 src/main/resources/application.properties 中配置。
debug=true
此外,配置 logging.level.* 來具體輸出哪些包的日誌級別。
例如
logging.level.root=INFO
logging.level.org.springframework.web=DEBUG
logging.level.cn.enjoy.controller=DEBUG
這個時候,包括springframework.web以及cn.enjoy.controller的debug日誌均可以輸出來了
通常狀況下,springboot日誌只會輸出到控制檯,並不會寫入到日誌文件,可是,在一些正式環境的應用中,咱們須要經過在 application.properites 文件中配置 logging.file 文件名稱和 logging.path 文件路徑,將日誌輸出到日誌文件中。
logging.path = /var/tmp
logging.file = xxx.log
logging.level.root = info
注意:
若是隻配置 logging.path,在 /var/tmp文件夾生成一個日誌文件爲 spring.log。若是隻配置 logging.file,會在項目的當前路徑下生成一個 xxx.log 日誌文件。
這裏有一個坑,logging.path 和logging.file都配置了,只會有logging.file生效,因此,若是要指定日誌生成的具體位置使用logging.file 配置就好
在application.properties中配置
logging.file =F:\\log\\enjoy.log
這樣在F盤的相應位置出現日誌文件
在spring-boot-dependencies POMs中搜索spring-boot-starter-log4j2
發現Spring boot父Pom中本身提供了這個依賴,因而咱們加入以下jar依賴:
修改pom.xml文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
注意: 因爲默認使用logback在擴展log4j2以前先要把logback移除
日誌使用跟上面logback同樣。
若是不僅爲了學習集成log4j,在工做是最好不要使用log4j,畢竟有了log4j2,也有了logback使用log4j就是吃飽了撐着
在springboot中並無提供對log4j這個依賴的支持,所以要使用它配置起來仍是挺麻煩的。
在: mvnrepository.com 中發現log4j最新版本spring-boot-starter-log4j是1.3.8.RELEASE
修改pom.xml文件
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j</artifactId> <version>1.3.8.RELEASE</version> </dependency> |
在classpath下增長log4j.properties文件
log4j.rootCategory=INFO, stdout, file, errorfile log4j.category.cn.enjoy=INFO, myFile log4j.logger.error=errorfile
# 控制檯輸出 log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n
# root日誌輸出 log4j.appender.file=org.apache.log4j.DailyRollingFileAppender log4j.appender.file.file=logs/all.log log4j.appender.file.DatePattern='.'yyyy-MM-dd log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n
# error日誌輸出 log4j.appender.errorfile=org.apache.log4j.DailyRollingFileAppender log4j.appender.errorfile.file=logs/error.log log4j.appender.errorfile.DatePattern='.'yyyy-MM-dd log4j.appender.errorfile.Threshold = ERROR log4j.appender.errorfile.layout=org.apache.log4j.PatternLayout log4j.appender.errorfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n
# cn.enjoy下的日誌輸出 log4j.appender.myFile=org.apache.log4j.DailyRollingFileAppender log4j.appender.myFile.file=logs/my.log log4j.appender.myFile.DatePattern='.'yyyy-MM-dd log4j.appender.myFile.layout=org.apache.log4j.PatternLayout log4j.appender.myFile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L ---- %m%n |
在代碼中使用
import org.apache.log4j.Logger;
private final Logger logger = Logger.getLogger(xxx.class);
爲了防止在工做中常常在代碼中加入大量的日誌處理代碼,在實際項目開發中,通常使用AOP統一完成日誌處理工做
修改pom文件,引入springboot對aop的支持
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> |
新增AOP日誌處理類
package cn.enjoy.utils;
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest; import java.util.Enumeration;
@Aspect @Component public class WebLogAspect {
private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
@Pointcut("execution(public * cn.enjoy.controller.*.*(..))") public void webLog() { }
@Before("webLog()") public void doBefore(JoinPoint joinPoint) throws Throwable { // 接收到請求,記錄請求內容 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 記錄下請求內容 logger.info("URL : " + request.getRequestURL().toString()); logger.info("HTTP_METHOD : " + request.getMethod()); logger.info("IP : " + request.getRemoteAddr()); Enumeration<String> enu = request.getParameterNames(); while (enu.hasMoreElements()) { String name = (String) enu.nextElement(); logger.info("name:{},value:{}", name, request.getParameter(name)); } }
@AfterReturning(returning = "ret", pointcut = "webLog()") public void doAfterReturning(Object ret) throws Throwable { // 處理完請求,返回內容 logger.info("RESPONSE : " + ret); } } |