day02項目【環(huán)境搭建和講師管理接口開發(fā)】

01-數據庫設計

一弃理、數據庫設計

二屿良、數據庫設計規(guī)約

以下規(guī)約只針對本模塊,更全面的文檔參考《阿里巴巴Java開發(fā)手冊》:五、MySQL數據庫

1按价、庫名與應用名稱盡量一致

2惭适、表名、字段名必須使用小寫字母或數字楼镐,禁止出現數字開頭癞志,

3、表名不使用復數名詞

4框产、表的命名最好是加上“業(yè)務名稱_表的作用”凄杯。如,edu_teacher

5秉宿、表必備三字段:id, gmt_create, gmt_modified

說明:

其中 id 必為主鍵戒突,類型為 bigint unsigned、單表時自增蘸鲸、步長為 1妖谴。

(如果使用分庫分表集群部署窿锉,則id類型為verchar酌摇,非自增,業(yè)務中使用分布式id生成器)

gmt_create, gmt_modified 的類型均為 datetime 類型嗡载,前者現在時表示主動創(chuàng)建窑多,后者過去分詞表示被 動更新。

6洼滚、單表行數超過 500 萬行或者單表容量超過 2GB埂息,才推薦進行分庫分表。 說明:如果預計三年后的數據量根本達不到這個級別遥巴,請不要在創(chuàng)建表時就分庫分表千康。?

7、表達是與否概念的字段铲掐,必須使用 is_xxx 的方式命名拾弃,數據類型是 unsigned tinyint (1 表示是,0 表示否)摆霉。?

說明:任何字段如果為非負數豪椿,必須是 unsigned。?

注意:POJO 類中的任何布爾類型的變量携栋,都不要加 is 前綴搭盾。數據庫表示是與否的值,使用 tinyint 類型婉支,堅持 is_xxx 的 命名方式是為了明確其取值含義與取值范圍鸯隅。?

正例:表達邏輯刪除的字段名 is_deleted,1 表示刪除向挖,0 表示未刪除蝌以。?

8霎奢、小數類型為 decimal,禁止使用 float 和 double饼灿。 說明:float 和 double 在存儲的時候幕侠,存在精度損失的問題,很可能在值的比較時碍彭,得到不 正確的結果晤硕。如果存儲的數據范圍超過 decimal 的范圍,建議將數據拆成整數和小數分開存儲庇忌。

9舞箍、如果存儲的字符串長度幾乎相等,使用 char 定長字符串類型皆疹。?

10疏橄、varchar 是可變長字符串,不預先分配存儲空間略就,長度不要超過 5000捎迫,如果存儲長度大于此值,定義字段類型為 text表牢,獨立出來一張表窄绒,用主鍵來對應,避免影響其它字段索 引效率崔兴。

11彰导、唯一索引名為 uk_字段名;普通索引名則為 idx_字段名敲茄。

說明:uk_ 即 unique key位谋;idx_ 即 index 的簡稱

12、不得使用外鍵與級聯堰燎,一切外鍵概念必須在應用層解決掏父。外鍵與級聯更新適用于單機低并發(fā),不適合分布式爽待、高并發(fā)集群损同;級聯更新是強阻塞,存在數據庫更新風暴的風險鸟款;外鍵影響數據庫的插入速度膏燃。?



02-搭建項目工程(父工程)

一、工程結構介紹

1何什、工程結構

2组哩、模塊說明

guli-parent:在線教學根目錄(父工程),管理四個子模塊:

?canal-client:canal數據庫表同步模塊(統(tǒng)計同步數據)

common:公共模塊父節(jié)點

? ??? ??common-util:工具類模塊,所有模塊都可以依賴于它

? ??? ??service-base:service服務的base包伶贰,包含service服務的公共配置類蛛砰,所有service模塊依賴于它

? ??? ??spring-security:認證與授權模塊,需要認證授權的service服務依賴于它

infrastructure:基礎服務模塊父節(jié)點

? ??? ??api-gateway:api網關服務

service:api接口服務父節(jié)點

service-acl:用戶權限管理api接口服務(用戶管理黍衙、角色管理和權限管理等)

service-cms:cms api接口服務

service-edu:教學相關api接口服務

service-msm:短信api接口服務

service-order:訂單相關api接口服務

service-oss:阿里云oss api接口服務

service-statistics:統(tǒng)計報表api接口服務

service-ucenter:會員api接口服務

service-vod:視頻點播api接口服務

二泥畅、創(chuàng)建父工程

1、創(chuàng)建sprigboot工程guli-parent

在idea開發(fā)工具中琅翻,使用?Spring Initializr?快速初始化一個?Spring Boot 模塊位仁,版本使用:2.2.1.RELEASE

2、配置 pom.xml

<artifactId>?節(jié)點后面添加 pom類型

3方椎、在pom.xml中添加依賴的版本

刪除pom.xml中的<dependencies>內容

<dependencies>

???????????????.......................

</dependencies>

添加?<properties>確定依賴的版本

配置<dependencyManagement>鎖定依賴的版本



03-搭建項目工程(service模塊)



2 講師管理接口開發(fā)

01-講師管理模塊配置和生成代碼

一聂抢、講師管理模塊配置

1、在service下面service-edu模塊中創(chuàng)建配置文件

resources目錄下創(chuàng)建文件?application.properties

# 服務端口

server.port=8001

# 服務名

spring.application.name=service-edu

# 環(huán)境設置:dev棠众、test琳疏、prod

spring.profiles.active=dev

spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false

spring.datasource.username=root

spring.datasource.password=123456

#mybatis日志

mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

或者在resources目錄下創(chuàng)建文件?application.yml

2、創(chuàng)建MP代碼生成器

在test/java目錄下創(chuàng)建包com.atguigu.eduservice闸拿,創(chuàng)建代碼生成器:CodeGenerator.java

package com.atguigu.demo;

import com.baomidou.mybatisplus.annotation.DbType;

import com.baomidou.mybatisplus.annotation.IdType;

import com.baomidou.mybatisplus.generator.AutoGenerator;

import com.baomidou.mybatisplus.generator.config.DataSourceConfig;

import com.baomidou.mybatisplus.generator.config.GlobalConfig;

import com.baomidou.mybatisplus.generator.config.PackageConfig;

import com.baomidou.mybatisplus.generator.config.StrategyConfig;

import com.baomidou.mybatisplus.generator.config.rules.DateType;

import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import org.junit.Test;

/**

* @author

* @since 2018/12/13

*/

public class CodeGenerator {

@Test

? ? public void run() {

// 1空盼、創(chuàng)建代碼生成器

? ? ? ? AutoGenerator mpg =new AutoGenerator();

// 2、全局配置

? ? ? ? GlobalConfig gc =new GlobalConfig();

String projectPath =System.getProperty("user.dir");

gc.setOutputDir("E:\\blog\\guli_parent\\service\\service_edu" +"/src/main/java");

gc.setAuthor("testjava");

gc.setOpen(false);//生成后是否打開資源管理器

? ? ? ? gc.setFileOverride(false);//重新生成時文件是否覆蓋

? ? ? ? //UserServie

? ? ? ? gc.setServiceName("%sService");//去掉Service接口的首字母I

? ? ? ? gc.setIdType(IdType.ID_WORKER_STR);//主鍵策略

? ? ? ? gc.setDateType(DateType.ONLY_DATE);//定義生成的實體類中日期類型

? ? ? ? gc.setSwagger2(true);//開啟Swagger2模式

? ? ? ? mpg.setGlobalConfig(gc);

// 3胸墙、數據源配置

? ? ? ? DataSourceConfig dsc =new DataSourceConfig();

dsc.setUrl("jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false");

dsc.setDriverName("com.mysql.jdbc.Driver");

dsc.setUsername("root");

dsc.setPassword("123456");

dsc.setDbType(DbType.MYSQL);

mpg.setDataSource(dsc);

// 4我注、包配置

? ? ? ? PackageConfig pc =new PackageConfig();

pc.setModuleName("eduservice");//模塊名

? ? ? ? //包com.atguigu.eduservice

? ? ? ? pc.setParent("com.atguigu");

//包com.atguigu.eduservice.controller

? ? ? ? pc.setController("controller");

pc.setEntity("entity");

pc.setService("service");

pc.setMapper("mapper");

mpg.setPackageInfo(pc);

// 5、策略配置

? ? ? ? StrategyConfig strategy =new StrategyConfig();

strategy.setInclude("edu_teacher");

strategy.setNaming(NamingStrategy.underline_to_camel);//數據庫表映射到實體的命名策略

? ? ? ? strategy.setTablePrefix(pc.getModuleName() +"_");//生成實體時去掉表前綴

? ? ? ? strategy.setColumnNaming(NamingStrategy.underline_to_camel);//數據庫表字段映射到實體的命名策略

? ? ? ? strategy.setEntityLombokModel(true);// lombok 模型 @Accessors(chain = true) setter鏈式操作

? ? ? ? strategy.setRestControllerStyle(true);//restful api風格控制器

? ? ? ? strategy.setControllerMappingHyphenStyle(true);//url中駝峰轉連字符

? ? ? ? mpg.setStrategy(strategy);

????????// 6迟隅、執(zhí)行

? ? ? ? mpg.execute();

}

}

二、編寫后臺管理api接口

1励七、編寫controller代碼

public class EduTeacherController {

????//把service注入

? ? @Autowired

? ? private EduTeacherService teacherService;

????//1 查詢講師表所有數據

? ? //rest風格

? ? //@GetMapping是一個組合注解智袭,是@RequestMapping(method = RequestMethod.GET)的縮寫

? ? @GetMapping("findAll")

????public List<EduTeacher> findAllTeacher(){

????????//調用service的方法實現查詢所有的操作

? ? ? ? List<EduTeacher> list =teacherService.list(null);

????????return list;

????}

}

2、創(chuàng)建SpringBoot啟動類

創(chuàng)建啟動類 EduApplication.java掠抬,注意啟動類的創(chuàng)建位置

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication

public class EduApplication {

????public static void main(String[] args) {

????????SpringApplication.run(EduApplication.class, args);

????}

}

3吼野、創(chuàng)建SpringBoot配置類

在edu包下創(chuàng)建config包,創(chuàng)建MyBatisPlusConfig.java

@Configuration

@MapperScan("com.atguigu.eduservice.mapper")

public class EduConfig {

}

4两波、配置SQL執(zhí)行性能分析插件

/**

* SQL 執(zhí)行性能分析插件

* 開發(fā)環(huán)境使用瞳步,線上不推薦。 maxTime 指的是 sql 最大執(zhí)行時長

*

*三種環(huán)境

* dev:開發(fā)環(huán)境

* test:測試環(huán)境

* prod:生產環(huán)境

*/

@Bean

@Profile({"dev","test"})// 設置 dev test 環(huán)境開啟

public PerformanceInterceptor performanceInterceptor() {

PerformanceInterceptor performanceInterceptor =new PerformanceInterceptor();

performanceInterceptor.setMaxTime(1000);//ms腰奋,超過此處設置的ms則sql不執(zhí)行

? ? performanceInterceptor.setFormat(true);

return performanceInterceptor;

}

5单起、運行啟動類

訪問http://localhost:8001/eduservice/teacher

得到json數據

成功:

6、統(tǒng)一返回的json時間格式

默認情況下json時間格式帶有時區(qū)劣坊,并且是世界標準時間嘀倒,和我們的時間差了八個小時

在application.properties中設置

#返回json的全局時間格式

spring.jackson.date-format=yyyy-MM-dd HH:mm:ss

spring.jackson.time-zone=GMT+8

三、講師邏輯刪除功能

1、配置邏輯刪除插件

MyBatisPlusConfig中配置

/**

* 邏輯刪除插件

*/

@Bean

public ISqlInjector sqlInjector() {

????return new LogicSqlInjector();

}

邏輯刪除注解:

@ApiModelProperty(value ="邏輯刪除 1(true)已刪除测蘑, 0(false)未刪除")

@TableLogic

private Boolean isDeleted;

2灌危、EduTeacherController添加刪除方法

//2 邏輯刪除講師的方法

@DeleteMapping("{id}")

public boolean removeTeacher(@PathVariable String id){

????return teacherService.removeById(id);

}



02-配置Swagger2生成API接口文檔

一、Swagger2介紹

前后端分離開發(fā)模式中碳胳,api文檔是最好的溝通方式勇蝙。

Swagger 是一個規(guī)范和完整的框架,用于生成挨约、描述浅蚪、調用和可視化 RESTful 風格的 Web 服務。

????1烫罩、及時性?(接口變更后惜傲,能夠及時準確地通知相關前后端開發(fā)人員)

????2、規(guī)范性?(并且保證接口的規(guī)范性贝攒,如接口的地址盗誊,請求方式,參數及響應格式和錯誤信息)

????3隘弊、一致性?(接口信息一致哈踱,不會出現因開發(fā)人員拿到的文檔版本不一致,而出現分歧)

????4梨熙、可測性?(直接在接口文檔上進行測試坤塞,以方便理解業(yè)務)

二、配置Swagger2

1蜘欲、創(chuàng)建common模塊

在guli-parent下創(chuàng)建模塊common

配置:

groupId:com.atguigu

artifactId:common

2洁段、在common中引入相關依賴

<dependencies>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? <artifactId>spring-boot-starter-web</artifactId>

? ? ? ? ? ? <scope>provided </scope>

? ? ? ? </dependency>

? ? ? ? <!--mybatis-plus-->

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>com.baomidou</groupId>

? ? ? ? ? ? <artifactId>mybatis-plus-boot-starter</artifactId>

? ? ? ? ? ? <scope>provided </scope>

? ? ? ? </dependency>

? ? ? ? <!--lombok用來簡化實體類:需要安裝lombok插件-->

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.projectlombok</groupId>

? ? ? ? ? ? <artifactId>lombok</artifactId>

? ? ? ? ? ? <scope>provided </scope>

? ? ? ? </dependency>

? ? ? ? <!--swagger-->

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>io.springfox</groupId>

? ? ? ? ? ? <artifactId>springfox-swagger2</artifactId>

? ? ? ? ? ? <scope>provided </scope>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>io.springfox</groupId>

? ? ? ? ? ? <artifactId>springfox-swagger-ui</artifactId>

? ? ? ? ? ? <scope>provided </scope>

? ? ? ? </dependency>

? ? ? ? <!-- redis -->

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? <artifactId>spring-boot-starter-data-redis</artifactId>

? ? ? ? </dependency>

? ? ? ? <!-- spring2.X集成redis所需common-pool2

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.apache.commons</groupId>

? ? ? ? ? ? <artifactId>commons-pool2</artifactId>

? ? ? ? ? ? <version>2.6.0</version>

? ? ? ? </dependency>-->

? ? </dependencies>

3、在common下面創(chuàng)建子模塊service-base

在模塊service-base中质欲,創(chuàng)建swagger的配置類

創(chuàng)建包com.atguigu.servicebase树埠,創(chuàng)建類SwaggerConfig

import com.google.common.base.Predicates;

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.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 //swagger注解

public class SwaggerConfig {

? ? @Bean

? ? public Docket webApiConfig(){

? ? ? ? return new Docket(DocumentationType.SWAGGER_2)

? ? ? ? ? ? ? ? .groupName("webApi")

? ? ? ? ? ? ? ? .apiInfo(webApiInfo())

? ? ? ? ? ? ? ? .select()

? ? ? ? ? ? ? ? .paths(Predicates.not(PathSelectors.regex("/admin/.*")))

? ? ? ? ? ? ? ? .paths(Predicates.not(PathSelectors.regex("/error.*")))

? ? ? ? ? ? ? ? .build();

? ? }

? ? private ApiInfo webApiInfo(){

? ? ? ? return new ApiInfoBuilder()

? ? ? ? ? ? ? ? .title("網站-課程中心API文檔")

? ? ? ? ? ? ? ? .description("本文檔描述了課程中心微服務接口定義")

? ? ? ? ? ? ? ? .version("1.0")

? ? ? ? ? ? ? ? .contact(new Contact("java", "http://atguigu.com", "123456@qq.com"))

? ? ? ? ? ? ? ? .build();

? ? }

}

4、在模塊service模塊中引入service-base

????????<dependency>

? ? ? ? ? ? <groupId>com.atguigu</groupId>

? ? ? ? ? ? <artifactId>service_base</artifactId>

? ? ? ? ? ? <version>0.0.1-SNAPSHOT</version>

? ? ? ? </dependency>

5嘶伟、在service-edu啟動類上添加注解怎憋,進行測試


訪問:http://localhost:8001/swagger-ui.html

測試刪除:

定義接口說明和參數說明:

????定義在類上:@Api

????定義在方法上:@ApiOperation

????定義在參數上:@ApiParam

@Api(description="講師管理")

@RestController

@RequestMapping("/eduservice/teacher")

public class EduTeacherController {

? ? //訪問地址http://localhost:8001/eduservice/teacher/findAll

? ? //把service注入

? ? @Autowired

? ? private EduTeacherService teacherService;

? ? //1 查詢講師表所有數據

? ? //rest風格

? ? //@GetMapping是一個組合注解,是@RequestMapping(method = RequestMethod.GET)的縮寫

? ? @ApiOperation(value = "所有講師列表")

? ? @GetMapping("findAll")

? ? public List<EduTeacher> findAllTeacher(){

? ? ? ? //調用service的方法實現查詢所有的操作

? ? ? ? List<EduTeacher> list = teacherService.list(null);

? ? ? ? return list;

? ? }

? ? //2 邏輯刪除講師的方法

? ? @ApiOperation(value = "根據ID刪除講師")

? ? @DeleteMapping("{id}")

? ? public boolean removeTeacher( @ApiParam(name = "id", value = "講師ID", required = true) @PathVariable String id){

? ? ? ? return teacherService.removeById(id);

? ? }

}

6九昧、API模型

可以添加一些自定義設置绊袋,例如:

定義樣例數據



03-統(tǒng)一返回結果對象

一、統(tǒng)一返回數據格式

項目中我們會將響應封裝成json返回铸鹰,一般我們會將所有接口的數據格式統(tǒng)一癌别, 使前端(iOS Android, Web)對數據的操作更一致、輕松掉奄。

一般情況下规个,統(tǒng)一返回數據格式沒有固定的格式凤薛,只要能描述清楚返回的數據狀態(tài)以及要返回的具體數據就可以。但是一般會包含狀態(tài)碼诞仓、返回消息缤苫、數據這幾部分內容

例如,我們的系統(tǒng)要求返回的基本數據格式如下:

列表:

分頁:

沒有返回數據:

失斒谩:

因此活玲,我們定義統(tǒng)一結果

{

????"success":布爾,//響應是否成功

????"code":數字,//響應碼

????"message":字符串,//返回消息

????"data":HashMap//返回數據,放在鍵值對中

}

二谍婉、創(chuàng)建統(tǒng)一結果返回類

1舒憾、在common模塊下創(chuàng)建子模塊common-utils

2、創(chuàng)建接口定義返回碼

創(chuàng)建包com.atguigu.commonutils穗熬,創(chuàng)建接口 ResultCode.java

package com.atguigu.commonutils;

public interface ResultCode {

? ? public static Integer SUCCESS = 20000; //成功

? ? public static Integer ERROR = 20001; //失敗

}

4镀迂、創(chuàng)建結果類

創(chuàng)建類 R.java

package com.atguigu.commonutils;

import io.swagger.annotations.ApiModelProperty;

import lombok.Data;

import java.util.HashMap;

import java.util.Map;

//統(tǒng)一返回結果的類

@Data

public class R {

? ? @ApiModelProperty(value = "是否成功")

? ? private Boolean success;

? ? @ApiModelProperty(value = "返回碼")

? ? private Integer code;

? ? @ApiModelProperty(value = "返回消息")

? ? private String message;

? ? @ApiModelProperty(value = "返回數據")

? ? private Map<String, Object> data = new HashMap<String, Object>();


????//把構造方法私有

????private R(){};


????//成功靜態(tài)方法

? ? public static R ok(){

? ? ? ? R r = new R();

? ? ? ? r.setSuccess(true);

? ? ? ? r.setCode(ResultCode.SUCCESS);

? ? ? ? r.setMessage("成功");

? ? ? ? return r;

? ? }


????//失敗靜態(tài)方法

? ? public static R error(){

? ? ? ? R r = new R();

? ? ? ? r.setSuccess(false);

? ? ? ? r.setCode(ResultCode.ERROR);

? ? ? ? r.setMessage("失敗");

? ? ? ? return r;

? ? }


? ? public R success(Boolean success){

? ? ? ? this.setSuccess(success);

? ? ? ? return this;

? ? }

? ? public R message(String message){

? ? ? ? this.setMessage(message);

? ? ? ? return this;

? ? }

? ? public R code(Integer code){

? ? ? ? this.setCode(code);

? ? ? ? return this;

? ? }

? ? public R data(String key, Object value){

? ? ? ? this.data.put(key, value);

? ? ? ? return this;

? ? }

? ? public R data(Map<String, Object> map){

? ? ? ? this.setData(map);

? ? ? ? return this;

? ? }

}

return this;的目的是為了鏈式編程如R.ok().success().message().code()

三、統(tǒng)一返回結果使用

1唤蔗、在service模塊中添加依賴

????????<dependency>

? ? ? ? ? ? <groupId>com.atguigu</groupId>

? ? ? ? ? ? <artifactId>common_utils</artifactId>

? ? ? ? ? ? <version>0.0.1-SNAPSHOT</version>

? ? ? ? </dependency>

2探遵、修改Controller中的返回結果

列表

????//1 查詢講師表所有數據

? ? //rest風格

? ? //@GetMapping是一個組合注解,是@RequestMapping(method = RequestMethod.GET)的縮寫

? ? @ApiOperation(value = "所有講師列表")

? ? @GetMapping("findAll")

? ? public R findAllTeacher(){

? ? ? ? //調用service的方法實現查詢所有的操作

? ? ? ? List<EduTeacher> list = teacherService.list(null);

? ? ? ? return R.ok().data("items",list);

? ? }

刪除

????//2 邏輯刪除講師的方法

? ? @ApiOperation(value = "根據ID刪除講師")

? ? @DeleteMapping("{id}")

? ? public R removeTeacher( @ApiParam(name = "id", value = "講師ID", required = true) @PathVariable String id){

? ? ? ? boolean flag = teacherService.removeById(id);

? ? ? ? if (flag) {

? ? ? ? ? ? return R.ok();

? ? ? ? }else {

? ? ? ? ? ? return R.error();

? ? ? ? }

? ? }



04-分頁和條件查詢接口開發(fā)

一妓柜、分頁

1箱季、MyBatisPlusConfig中配置分頁插件

????/**

? ? * 分頁插件

? ? */

? ? @Bean

? ? public PaginationInterceptor paginationInterceptor() {

? ? ? ? return new PaginationInterceptor();

? ? }

2、分頁Controller方法

TeacherAdminController中添加分頁方法

????//3 分頁查詢講師的方法

? ? //current 當前頁

? ? //limit 每頁記錄數

? ? @ApiOperation(value = "分頁講師列表")

? ? @GetMapping("pageTeacher/{current}/{limit}")

? ? public R pageListTeacher(@ApiParam(name = "current", value = "當前頁碼", required = true) @PathVariable long current,

? ? ? ? ? ? ? ? ? ? ? ? ? ? @ApiParam(name = "limit", value = "每頁記錄數", required = true) @PathVariable long limit){

? ? ? ? //創(chuàng)建page對象

? ? ? ? Page<EduTeacher> pageTacher = new Page<>(current,limit);

? ? ? ? //調用方法實現分頁

? ? ? ? //調用方法的時候棍掐,底層封裝藏雏,把分頁所有數據封裝到pageTeacher對象里面

? ? ? ? teacherService.page(pageTacher,null);

? ? ? ? long total = pageTacher.getTotal(); //總記錄數

? ? ? ? List<EduTeacher> records = pageTacher.getRecords(); //數據list集合


//? ? ? ? Map map = new HashMap();

//? ? ? ? map.put("total",total);

//? ? ? ? map.put("rows",records);

//? ? ? ? return R.ok().data(map);


? ? ? ? return R.ok().data("total",total).data("rows",records);

3、Swagger中測試

二作煌、條件查詢

根據講師名稱name掘殴,講師頭銜level、講師入駐時間gmt_create(時間段)查詢

1最疆、創(chuàng)建查詢對象

創(chuàng)建com.guli.edu.query包杯巨,創(chuàng)建TeacherQuery.java查詢對象

import io.swagger.annotations.ApiModel;

import io.swagger.annotations.ApiModelProperty;

import lombok.Data;

@ApiModel(value = "Teacher查詢對象", description = "講師查詢對象封裝")

@Data

public class TeacherQuery {

? ? @ApiModelProperty(value = "教師名稱,模糊查詢")

? ? private String name;

? ? @ApiModelProperty(value = "頭銜 1高級講師 2首席講師")

? ? private Integer level;

? ? @ApiModelProperty(value = "查詢開始時間",example = "2019-01-01 10:10:10")

? ? private String begin;

? ? @ApiModelProperty(value = "查詢結束時間",example = "2019-12-01 10:10:10")

? ? private String end;

}

2、service

接口

public interface EduTeacherService extends IService<EduTeacher> {

? ? void pageQuery(Page<EduTeacher> pageParam,TeacherQuery teacherQuery);

}

實現

????@Override

? ? public void pageQuery(Page<EduTeacher> pageTacher, TeacherQuery teacherQuery) {

? ? ? ? QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();

? ? ? ? wrapper.orderByAsc("sort");


? ? ? ? if (teacherQuery == null){

? ? ? ? ? ? baseMapper.selectPage(pageTacher,wrapper);

? ? ? ? ? ? return;

? ? ? ? }


? ? ? ? String name = teacherQuery.getName();

? ? ? ? Integer level = teacherQuery.getLevel();

? ? ? ? String begin = teacherQuery.getBegin();

? ? ? ? String end = teacherQuery.getEnd();


? ? ? ? if (!StringUtils.isEmpty(name)){

? ? ? ? ? ? wrapper.like("name",name);

? ? ? ? }

? ? ? ? if (!StringUtils.isEmpty(level)){

? ? ? ? ? ? wrapper.eq("level",level);

? ? ? ? }

? ? ? ? if (!StringUtils.isEmpty(begin)){

? ? ? ? ? ? wrapper.ge("gmt_create",begin);

? ? ? ? }

? ? ? ? if (!StringUtils.isEmpty(end)){

? ? ? ? ? ? wrapper.le("gmt_modified",end);

? ? ? ? }

? ? ? ? baseMapper.selectPage(pageTacher,wrapper);

? ? }

3努酸、controller

TeacherAdminController中修改 pageList方法:

增加參數TeacherQuery teacherQuery,非必選

????//4 條件查詢帶分頁的方法

? ? @ApiOperation(value = "分頁講師列表")

? ? @GetMapping("pageTeacherCondition/{current}/{limit}")

? ? public R pageTeacherCondition(@ApiParam(name = "current", value = "當前頁碼", required = true) @PathVariable long current,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @ApiParam(name = "limit", value = "每頁記錄數", required = true) @PathVariable long limit,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TeacherQuery teacherQuery){

? ? ? ? //創(chuàng)建page對象

? ? ? ? Page<EduTeacher> pageTacher = new Page<>(current,limit);

? ? ? ? //構建條件

? ? ? ? QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();

? ? ? ? //wrapper

? ? ? ? //調用方法實現條件查詢分頁

? ? ? ? teacherService.pageQuery(pageTacher,teacherQuery);


? ? ? ? long total = pageTacher.getTotal(); //總記錄數

? ? ? ? List<EduTeacher> records = pageTacher.getRecords(); //數據list集合

//? ? ? ? Map map = new HashMap();

//? ? ? ? map.put("total",total);

//? ? ? ? map.put("rows",records);

//? ? ? ? return R.ok().data(map);

? ? ? ? return R.ok().data("total",total).data("rows",records);

? ? }

4杜恰、Swagger中測試

http://localhost:8001/swagger-ui.html#/

????//4 條件查詢帶分頁的方法

? ? @ApiOperation(value = "分頁講師列表")

? ? @PostMapping("pageTeacherCondition/{current}/{limit}")

? ? public R pageTeacherCondition(@ApiParam(name = "current", value = "當前頁碼", required = true) @PathVariable long current,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @ApiParam(name = "limit", value = "每頁記錄數", required = true) @PathVariable long limit,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @RequestBody(required = false) TeacherQuery teacherQuery){

? ? ? ? //創(chuàng)建page對象

? ? ? ? Page<EduTeacher> pageTacher = new Page<>(current,limit);

? ? ? ? //構建條件

? ? ? ? QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();

? ? ? ? //wrapper

? ? ? ? //調用方法實現條件查詢分頁

? ? ? ? teacherService.pageQuery(pageTacher,teacherQuery);

? ? ? ? long total = pageTacher.getTotal(); //總記錄數

? ? ? ? List<EduTeacher> records = pageTacher.getRecords(); //數據list集合

//? ? ? ? Map map = new HashMap();

//? ? ? ? map.put("total",total);

//? ? ? ? map.put("rows",records);

//? ? ? ? return R.ok().data(map);

? ? ? ? return R.ok().data("total",total).data("rows",records);

? ? }

測試結果:



05-新增和修改講師接口開發(fā)

一获诈、自動填充封裝

1、在service-base模塊中添加

創(chuàng)建包handler心褐,創(chuàng)建自動填充類 MyMetaObjectHandler

@Component

public class MyMetaObjectHandler implements MetaObjectHandler {

? ? @Override

? ? public void insertFill(MetaObject metaObject) {

? ? ? ? this.setFieldValByName("gmtCreate",new Date(),metaObject);

? ? ? ? this.setFieldValByName("gmtModified", new Date(), metaObject);

? ? }

? ? @Override

? ? public void updateFill(MetaObject metaObject) {

? ? ? ? this.setFieldValByName("gmtModified", new Date(), metaObject);

? ? }

}

2舔涎、在實體類添加自動填充注解

????@ApiModelProperty(value = "創(chuàng)建時間", example = "2019-01-01 8:00:00")

? ? @TableField(fill = FieldFill.INSERT)

? ? private Date gmtCreate;


? ? @ApiModelProperty(value = "更新時間", example = "2019-01-01 8:00:00")

? ? @TableField(fill = FieldFill.INSERT_UPDATE)

? ? private Date gmtModified;

二、controller方法定義

1逗爹、新增

????//5 添加講師接口的方法

? ? //通過對象傳遞數據@RequestBody

? ? @ApiOperation(value = "新增講師")

? ? @PostMapping("addTeacher")

? ? public R save(@ApiParam(name = "eduTeacher", value = "講師對象", required = true)

? ? ? ? ? ? ? ? ? @RequestBody EduTeacher eduTeacher){

? ? ? ? boolean save = teacherService.save(eduTeacher);

? ? ? ? if (save) {

? ? ? ? ? ? return R.ok();

? ? ? ? }else {

? ? ? ? ? ? return R.error();

? ? ? ? }

? ? }

2亡嫌、根據id查詢

????//根據講師id查詢

? ? @ApiOperation(value = "根據id查詢講師")

? ? @GetMapping("getTeacher/{id}")

? ? public R getById(@ApiParam(name = "id", value = "講師ID", required = true)

? ? ? ? ? ? ? ? ? ? ? ? @PathVariable String id){

? ? ? ? EduTeacher eduTeacher = teacherService.getById(id);

? ? ? ? return R.ok().data("teacher",eduTeacher);

? ? }

3嚎于、根據id修改

或:

????//講師修改功能

? ? @ApiOperation(value = "根據ID修改講師")

? ? @PostMapping("updateTeacher")

? ? public R updateTeacher(@RequestBody EduTeacher eduTeacher){

? ? ? ? boolean flag = teacherService.updateById(eduTeacher);

? ? ? ? if (flag) {

? ? ? ? ? ? return R.ok();

? ? ? ? }else {

? ? ? ? ? ? return R.error();

? ? ? ? }

? ? }



06-統(tǒng)一異常處理

一、什么是統(tǒng)一異常處理

我們想讓異常結果也顯示為統(tǒng)一的返回結果對象挟冠,并且統(tǒng)一處理系統(tǒng)的異常信息于购,那么需要統(tǒng)一異常處理

二、統(tǒng)一異常處理

1知染、創(chuàng)建統(tǒng)一異常處理器

在service-base中創(chuàng)建統(tǒng)一異常處理類GlobalExceptionHandler.java:

//統(tǒng)一異常處理類

@ControllerAdvice

public class GlobalExceptionHandler {

? ? //指定出現什么異常執(zhí)行這個方法

? ? @ExceptionHandler(Exception.class)

? ? @ResponseBody //為了返回數據

? ? public R error(Exception e){

? ? ? ? e.printStackTrace();

? ? ? ? return R.error().message("執(zhí)行了全局異常處理...");

? ? }

}

在service_base中添加依賴:

刪除service中的

測試:

三肋僧、處理特定異常

1、添加異常處理方法

@ExceptionHandler(Exception.class)

//特定異常

? ? @ExceptionHandler(ArithmeticException.class)

? ? @ResponseBody //為了返回數據

? ? public R error(ArithmeticException e){

? ? ? ? e.printStackTrace();

? ? ? ? return R.error().message("執(zhí)行了ArithmeticException異常處理...");

? ? }

四控淡、自定義異常

1嫌吠、創(chuàng)建自定義異常類

@AllArgsConstructor //生成有參數的構造方法

@NoArgsConstructor //生成無參數的構造方法

@Data

@AllArgsConstructor //生成有參數的構造方法

@NoArgsConstructor //生成無參數的構造方法

public class GuliException extends RuntimeException {

? ? @ApiModelProperty(value = "狀態(tài)碼")

? ? private Integer code;

? ? @ApiModelProperty(value = "異常信息")

? ? private String msg;

}

2、業(yè)務中需要的位置拋出GuliException

????try {

? ? ? ? ? ? int a = 10/0;

? ? ? ? }catch (Exception e){

? ? ? ? ? ? //執(zhí)行自定義異常

? ? ? ? ? ? throw new GuliException(20001,"出現自定義異常");

? ? ? ? }

3掺炭、添加異常處理方法

GlobalExceptionHandler.java中添加

????//自定義異常

? ? @ExceptionHandler(GuliException.class)

? ? @ResponseBody //為了返回數據

? ? public R error(GuliException e){

? ? ? ? e.printStackTrace();

? ? ? ? return R.error().code(e.getCode()).message(e.getMsg());

? ? }

4辫诅、測試


07-統(tǒng)一日志處理

一、日志

1涧狮、配置日志級別

日志記錄器(Logger)的行為是分等級的炕矮。如下表所示:

分為:OFF、FATAL勋篓、ERROR吧享、WARN、INFO譬嚣、DEBUG钢颂、ALL

默認情況下,spring boot從控制臺打印出來的日志級別只有INFO及以上級別拜银,可以配置日志級別

# 設置日志級別

logging.level.root=INFO

這種方式只能將日志打印在控制臺上

二殊鞭、Logback日志

spring boot內部使用Logback作為日志實現的框架。

Logback和log4j非常相似尼桶,如果你對log4j很熟悉操灿,那對logback很快就會得心應手。

logback相對于log4j的一些優(yōu)點:https://blog.csdn.net/caisini_vc/article/details/48551287

1泵督、配置logback日志

刪除application.properties中的日志配置

安裝idea彩色日志插件:grep-console

resources 中創(chuàng)建 logback-spring.xml?

<?xml version="1.0" encoding="UTF-8"?>

<configuration? scan="true" scanPeriod="10 seconds">

? ? <!-- 日志級別從低到高分為TRACE < DEBUG < INFO < WARN < ERROR < FATAL趾盐,如果設置為WARN,則低于WARN的信息都不會輸出 -->

? ? <!-- scan:當此屬性設置為true時小腊,配置文件如果發(fā)生改變救鲤,將會被重新加載,默認值為true -->

? ? <!-- scanPeriod:設置監(jiān)測配置文件是否有修改的時間間隔秩冈,如果沒有給出時間單位本缠,默認單位是毫秒。當scan為true時入问,此屬性生效丹锹。默認的時間間隔為1分鐘稀颁。 -->

? ? <!-- debug:當此屬性設置為true時,將打印出logback內部日志信息楣黍,實時查看logback運行狀態(tài)匾灶。默認值為false。 -->

? ? <contextName>logback</contextName>

? ? <!-- name的值是變量的名稱锡凝,value的值時變量定義的值粘昨。通過定義的值會被插入到logger上下文中。定義變量后窜锯,可以使“${}”來使用變量张肾。 -->

? ? <property name="log.path" value="D:/guli_log/edu" />

? ? <!-- 彩色日志 -->

? ? <!-- 配置格式變量:CONSOLE_LOG_PATTERN 彩色日志格式 -->

? ? <!-- magenta:洋紅 -->

? ? <!-- boldMagenta:粗紅-->

? ? <!-- cyan:青色 -->

? ? <!-- white:白色 -->

? ? <!-- magenta:洋紅 -->

? ? <property name="CONSOLE_LOG_PATTERN"

? ? value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>

? ? <!--輸出到控制臺-->

? ? <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">

? ? ? ? <!--此日志appender是為開發(fā)使用,只配置最底級別锚扎,控制臺輸出的日志級別是大于或等于此級別的日志信息-->

? ? ? ? <!-- 例如:如果此處配置了INFO級別吞瞪,則后面其他位置即使配置了DEBUG級別的日志,也不會被輸出 -->

? ? ? ? <filter class="ch.qos.logback.classic.filter.ThresholdFilter">

? ? ? ? ? ? <level>INFO</level>

? ? ? ? </filter>

? ? ? ? <encoder>

? ? ? ? ? ? <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>

? ? ? ? ? ? <!-- 設置字符集 -->

? ? ? ? ? ? <charset>UTF-8</charset>

? ? ? ? </encoder>

? ? </appender>

? ? <!--輸出到文件-->

? ? <!-- 時間滾動輸出 level為 INFO 日志 -->

? ? <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">

? ? ? ? <!-- 正在記錄的日志文件的路徑及文件名 -->

? ? ? ? <file>${log.path}/log_info.log</file>

? ? ? ? <!--日志文件輸出格式-->

? ? ? ? <encoder>

? ? ? ? ? ? <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>

? ? ? ? ? ? <charset>UTF-8</charset>

? ? ? ? </encoder>

? ? ? ? <!-- 日志記錄器的滾動策略驾孔,按日期芍秆,按大小記錄 -->

? ? ? ? <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

? ? ? ? ? ? <!-- 每天日志歸檔路徑以及格式 -->

? ? ? ? ? ? <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>

? ? ? ? ? ? <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">

? ? ? ? ? ? ? ? <maxFileSize>100MB</maxFileSize>

? ? ? ? ? ? </timeBasedFileNamingAndTriggeringPolicy>

? ? ? ? ? ? <!--日志文件保留天數-->

? ? ? ? ? ? <maxHistory>15</maxHistory>

? ? ? ? </rollingPolicy>

? ? ? ? <!-- 此日志文件只記錄info級別的 -->

? ? ? ? <filter class="ch.qos.logback.classic.filter.LevelFilter">

? ? ? ? ? ? <level>INFO</level>

? ? ? ? ? ? <onMatch>ACCEPT</onMatch>

? ? ? ? ? ? <onMismatch>DENY</onMismatch>

? ? ? ? </filter>

? ? </appender>

? ? <!-- 時間滾動輸出 level為 WARN 日志 -->

? ? <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">

? ? ? ? <!-- 正在記錄的日志文件的路徑及文件名 -->

? ? ? ? <file>${log.path}/log_warn.log</file>

? ? ? ? <!--日志文件輸出格式-->

? ? ? ? <encoder>

? ? ? ? ? ? <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>

? ? ? ? ? ? <charset>UTF-8</charset> <!-- 此處設置字符集 -->

? ? ? ? </encoder>

? ? ? ? <!-- 日志記錄器的滾動策略,按日期翠勉,按大小記錄 -->

? ? ? ? <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

? ? ? ? ? ? <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>

? ? ? ? ? ? <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">

? ? ? ? ? ? ? ? <maxFileSize>100MB</maxFileSize>

? ? ? ? ? ? </timeBasedFileNamingAndTriggeringPolicy>

? ? ? ? ? ? <!--日志文件保留天數-->

? ? ? ? ? ? <maxHistory>15</maxHistory>

? ? ? ? </rollingPolicy>

? ? ? ? <!-- 此日志文件只記錄warn級別的 -->

? ? ? ? <filter class="ch.qos.logback.classic.filter.LevelFilter">

? ? ? ? ? ? <level>warn</level>

? ? ? ? ? ? <onMatch>ACCEPT</onMatch>

? ? ? ? ? ? <onMismatch>DENY</onMismatch>

? ? ? ? </filter>

? ? </appender>

? ? <!-- 時間滾動輸出 level為 ERROR 日志 -->

? ? <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">

? ? ? ? <!-- 正在記錄的日志文件的路徑及文件名 -->

? ? ? ? <file>${log.path}/log_error.log</file>

? ? ? ? <!--日志文件輸出格式-->

? ? ? ? <encoder>

? ? ? ? ? ? <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>

? ? ? ? ? ? <charset>UTF-8</charset> <!-- 此處設置字符集 -->

? ? ? ? </encoder>

? ? ? ? <!-- 日志記錄器的滾動策略妖啥,按日期,按大小記錄 -->

? ? ? ? <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

? ? ? ? ? ? <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>

? ? ? ? ? ? <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">

? ? ? ? ? ? ? ? <maxFileSize>100MB</maxFileSize>

? ? ? ? ? ? </timeBasedFileNamingAndTriggeringPolicy>

? ? ? ? ? ? <!--日志文件保留天數-->

? ? ? ? ? ? <maxHistory>15</maxHistory>

? ? ? ? </rollingPolicy>

? ? ? ? <!-- 此日志文件只記錄ERROR級別的 -->

? ? ? ? <filter class="ch.qos.logback.classic.filter.LevelFilter">

? ? ? ? ? ? <level>ERROR</level>

? ? ? ? ? ? <onMatch>ACCEPT</onMatch>

? ? ? ? ? ? <onMismatch>DENY</onMismatch>

? ? ? ? </filter>

? ? </appender>

? ? <!--

? ? ? ? <logger>用來設置某一個包或者具體的某一個類的日志打印級別对碌、以及指定<appender>荆虱。

? ? ? ? <logger>僅有一個name屬性,

? ? ? ? 一個可選的level和一個可選的addtivity屬性朽们。

? ? ? ? name:用來指定受此logger約束的某一個包或者具體的某一個類怀读。

? ? ? ? level:用來設置打印級別,大小寫無關:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF骑脱,

? ? ? ? ? ? ? 如果未設置此屬性菜枷,那么當前l(fā)ogger將會繼承上級的級別。

? ? -->

? ? <!--

? ? ? ? 使用mybatis的時候叁丧,sql語句是debug下才會打印啤誊,而這里我們只配置了info,所以想要查看sql語句的話拥娄,有以下兩種操作:

? ? ? ? 第一種把<root level="INFO">改成<root level="DEBUG">這樣就會打印sql坷衍,不過這樣日志那邊會出現很多其他消息

? ? ? ? 第二種就是單獨給mapper下目錄配置DEBUG模式,代碼如下条舔,這樣配置sql語句會打印,其他還是正常DEBUG級別:

? ? -->

? ? <!--開發(fā)環(huán)境:打印控制臺-->

? ? <springProfile name="dev">

? ? ? ? <!--可以輸出項目中的debug日志乏矾,包括mybatis的sql日志-->

? ? ? ? <logger name="com.guli" level="INFO" />

? ? ? ? <!--

? ? ? ? ? ? root節(jié)點是必選節(jié)點孟抗,用來指定最基礎的日志輸出級別迁杨,只有一個level屬性

? ? ? ? ? ? level:用來設置打印級別,大小寫無關:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF凄硼,默認是DEBUG

? ? ? ? ? ? 可以包含零個或多個appender元素铅协。

? ? ? ? -->

? ? ? ? <root level="INFO">

? ? ? ? ? ? <appender-ref ref="CONSOLE" />

? ? ? ? ? ? <appender-ref ref="INFO_FILE" />

? ? ? ? ? ? <appender-ref ref="WARN_FILE" />

? ? ? ? ? ? <appender-ref ref="ERROR_FILE" />

? ? ? ? </root>

? ? </springProfile>

? ? <!--生產環(huán)境:輸出到文件-->

? ? <springProfile name="pro">

? ? ? ? <root level="INFO">

? ? ? ? ? ? <appender-ref ref="CONSOLE" />

? ? ? ? ? ? <appender-ref ref="DEBUG_FILE" />

? ? ? ? ? ? <appender-ref ref="INFO_FILE" />

? ? ? ? ? ? <appender-ref ref="ERROR_FILE" />

? ? ? ? ? ? <appender-ref ref="WARN_FILE" />

? ? ? ? </root>

? ? </springProfile>

</configuration>

2、將錯誤日志輸出到文件

GlobalExceptionHandler.java 中

類上添加注解

異常輸出語句

3摊沉、將日志堆棧信息輸出到文件

定義工具類

guli-framework-common下創(chuàng)建util包狐史,創(chuàng)建ExceptionUtil.java工具類

public class ExceptionUtil {

? ? public static String getMessage(Exception e){

? ? ? ? StringWriter sw =null;

? ? ? ? PrintWriter pw = null;

? ? ? ? try {

? ? ? ? ? ? sw = new StringWriter();

? ? ? ? ? ? pw = new PrintWriter(sw);

? ? ? ? ? ? // 將出錯的棧信息輸出到printWriter中

? ? ? ? ? ? e.printStackTrace(pw);

? ? ? ? ? ? pw.flush();

? ? ? ? ? ? sw.flush();

? ? ? ? }finally {

? ? ? ? ? ? if (sw!= null){

? ? ? ? ? ? ? ? try {

? ? ? ? ? ? ? ? ? ? sw.close();

? ? ? ? ? ? ? ? }catch (IOException e1){

? ? ? ? ? ? ? ? ? ? e1.printStackTrace();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? if (pw!=null){

? ? ? ? ? ? ? ? pw.close();

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? return sw.toString();

? ? }

}

調用

log.error(ExceptionUtil.getMessage(e));

GuliException中創(chuàng)建toString方法

@Override

? ? public String toString() {

? ? ? ? return "GuliException{" +

? ? ? ? ? ? ? ? "code=" + code +

? ? ? ? ? ? ? ? ", message='" + this.getMessage() + '\'' +

? ? ? ? ? ? ? ? '}';

? ? }

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市说墨,隨后出現的幾起案子骏全,更是在濱河造成了極大的恐慌,老刑警劉巖尼斧,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姜贡,死亡現場離奇詭異,居然都是意外死亡棺棵,警方通過查閱死者的電腦和手機楼咳,發(fā)現死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烛恤,“玉大人母怜,你說我怎么就攤上這事「堪兀” “怎么了苹熏?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長船惨。 經常有香客問我柜裸,道長,這世上最難降的妖魔是什么粱锐? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任疙挺,我火速辦了婚禮,結果婚禮上怜浅,老公的妹妹穿的比我還像新娘铐然。我一直安慰自己,他們只是感情好恶座,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布搀暑。 她就那樣靜靜地躺著,像睡著了一般跨琳。 火紅的嫁衣襯著肌膚如雪自点。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天脉让,我揣著相機與錄音桂敛,去河邊找鬼功炮。 笑死,一個胖子當著我的面吹牛术唬,可吹牛的內容都是我干的薪伏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼粗仓,長吁一口氣:“原來是場噩夢啊……” “哼嫁怀!你這毒婦竟也來了?” 一聲冷哼從身側響起借浊,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤塘淑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后巴碗,有當地人在樹林里發(fā)現了一具尸體朴爬,經...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年橡淆,在試婚紗的時候發(fā)現自己被綠了召噩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡逸爵,死狀恐怖具滴,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情师倔,我是刑警寧澤构韵,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站趋艘,受9級特大地震影響疲恢,放射性物質發(fā)生泄漏谤民。R本人自食惡果不足惜豆混,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一念祭、第九天 我趴在偏房一處隱蔽的房頂上張望条霜。 院中可真熱鬧,春花似錦档址、人聲如沸年叮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽揍移。三九已至,卻和暖如春反肋,著一層夾襖步出監(jiān)牢的瞬間那伐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留喧锦,地道東北人读规。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像燃少,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子铃在,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355