一旦现实情况和脑海中预想的“应该”不符合,负面情绪就会奔涌而出,因为你的“世界秩序”崩塌了!
举例:在8081这个工程的前端只能去访问8081的后台,不能访问8082(不同的域)。这是浏览器的保护机制,但是我们可以通过某些设置,让前端页面可以访问不同的域。
跨域:浏览器+ajax+请求不同的域。
不同的域:协议+ip+端口,只要有一个不一样就是不同的域
浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域 。前后端分离开发中,需要考虑ajax跨域的问题。
解决办法:在Controller类上添加注解
@CrossOrigin //跨域
Swagger2(丝袜):用来实时自动的生成一个api接口文档
参数通常后端定,返回值前端定,Swagger2也可以当做postman使用
Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。
当通过 Swagger 正确定义时,消费者可以使用最少量的实现逻辑来理解远程服务并与其进行交互。因此,Swagger 消除了调用服务时的猜测。
swagger引入的主要依赖
-
- <dependency>
- <groupId>io.springfoxgroupId>
- <artifactId>springfox-swagger2artifactId>
- dependency>
- <dependency>
- <groupId>io.springfoxgroupId>
- <artifactId>springfox-swagger-uiartifactId>
- dependency>
创建swagger的配置类
创建类Swagger2Config,配置文档的基本信息
- @Configuration
- @EnableSwagger2
- public class Swagger2Config {
-
- @Bean
- public Docket webApiConfig(){
- return new Docket(DocumentationType.SWAGGER_2)
- .groupName("webApi")
- .apiInfo(webApiInfo())
- .select()
- //只显示api路径下的页面
- //.paths(Predicates.and(PathSelectors.regex("/api/.*")))
- .build();
- }
-
- private ApiInfo webApiInfo(){
- return new ApiInfoBuilder()
- .title("网站-API文档")
- .description("微服务接口文档")
- .version("1.0")
- .contact(new Contact("atguigu", "http://atguigu.com", "111222333@qq.com"))
- .build();
- }
-
- }
http://localhost:8201/swagger-ui.html
Swagger2定义接口说明和参数说明
使用sw注解标注在类上、方法上、参数上,返回值实体类上,用来进行功能的描述
标注在Controller类上:@Api
定义在方法上:@ApiOperation
定义在参数上:@ApiParam
用在实体类的属性上:@ApiModelProperty
用在模型类上: @ApiModel
//医院设置接口 @Api(description = "医院设置接口") @RestController @RequestMapping("/admin/hosp/hospitalSet") public class HospitalSetController { @Autowired private HospitalSetService hospitalSetService; @ApiOperation(value = "根据id删除") @DeleteMapping("{id}") public R removeById(@ApiParam(name = "id", value = "医院设置主键", required = true) @PathVariable Long id) { boolean b = hospitalSetService.removeById(id); return R.ok(); } }http://localhost:8201/swagger-ui.html#!/hospital45set45controller/removeByIdUsingDELETE
可以再配置一个webApiConfig组,用来显示不同的controller
作用:统一返回数据格式
项目中一般我们会将所有接口的数据格式统一,并返回json给前端, 使前端对数据的操作更一致、轻松。
一般会包括:数据状态、状态码、返回消息、数据
在我们系统中状态码有俩种 20000成功 20001失败
public class ResultCode { public static Integer SUCCESS = 20000; public static Integer ERROR = 20001; }
创建的R类如下,可参考
- @Data
- @ApiModel(description = "通用的返回结果类")
- public class R {
-
- @ApiModelProperty(value = "是否成功")
- private Boolean success;
-
- @ApiModelProperty(value = "返回码")
- private Integer code;
-
- @ApiModelProperty(value = "返回消息")
- private String message;
-
- @ApiModelProperty(value = "返回数据")
- private Map
data = new HashMap(); -
- private R(){}
-
- public static R ok(){
- R r = new R();
- r.setSuccess(true);
- r.setCode(ResultCode.SUCCESS);
- r.setMessage("成功");
- return r;
- }
- 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
map) { - this.setData(map);
- return this;
- }
- }
测试 R类的效果:
1.分页查询所有医院设置,代码很简单,如下使用MybatisPlus
@ApiOperation(value = "分页查询") @GetMapping("{page}/{limit}") public R pageList(@PathVariable("page") Long page, @PathVariable("limit") Long limit) { //参数校验一般写在service层 //page第几页 limit每页几条 PagepageParam = new Page<>(page, limit); hospitalSetService.page(pageParam, null); //从分页对象获取分页数据 Listrows = pageParam.getRecords(); //总记录数 long total = pageParam.getTotal(); return R.ok().data("total", total).data("rows", rows); }在Swagger上测试,查看R类有没有生效,效果如下图,是R类生效了的
让异常结果也显示为统一的返回结果对象,并且统一处理系统的异常信息,那么需要
统一异常处理器
1.不使用统一的异常处理器之前,看看效果
2.使用统一的异常处理器之后的返回值如下:
全局的异常处理器定义如下:@Slf4j和log.error不是必须得,可以没有,这俩货就是为了记录日志的。
@ControllerAdvice @Slf4j public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) @ResponseBody public R error(Exception ex){ //ex表示当前请求处理中出现的异常对象 log.error(ex.getMessage()); return R.error().message(ex.getMessage()); } }
自定义异常YyghException
@Data @NoArgsConstructor @AllArgsConstructor public class YyghException extends RuntimeException { private String msg; private Integer code; }在GlobalExceptionHandler中加入以下特定的自定义的异常
@ExceptionHandler(YyghException.class) @ResponseBody public R error(YyghException e){ //e表示当前请求处理中出现的异常对象 log.error(e.getMsg());//记录一条error级别的日志 return R.error().message(e.getMsg()).code(e.getCode()); }自定义异常的使用
try { int a = 10/0; } catch (Exception e) { throw new YyghException("自定义异常", ResultCode.ERROR); }测试:此时出现自定义异常走的是下面这个,越精确越好
日志记录器(Logger)的行为是分等级的。
分为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL
OFF 不打印 ALL 都打印如果设置的是info级别,则info级别的前面所有级别的日志都打印
- # 设置日志级别,这种方式只能将日志打印在控制台上
- logging.level.root=WARN
Logback日志
希望将日志记录在文件中,spring boot内部使用Logback作为日志实现的框架。
1.删除application.properties中的日志配置
#logging.level.root=warn
2.resources 中创建 logback-spring.xml
每一个微服务都可以使用这个日志配置文件,但是要注意修改“log.path”的值
- <configuration scan="true" scanPeriod="10 seconds">
-
-
-
-
-
- <contextName>logbackcontextName>
-
- <property name="log.path" value="E:/yygh_log/service_hosp"/>
-
-
-
-
-
-
-
-
- <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">
-
-
- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
- <level>INFOlevel>
- filter>
- <encoder>
- <Pattern>${CONSOLE_LOG_PATTERN}Pattern>
-
- <charset>UTF-8charset>
- encoder>
- appender>
-
-
-
-
-
- <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
-
- <file>${log.path}/log_info.logfile>
-
- <encoder>
- <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
- <charset>UTF-8charset>
- encoder>
-
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
-
- <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.logfileNamePattern>
- <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
- <maxFileSize>100MBmaxFileSize>
- timeBasedFileNamingAndTriggeringPolicy>
-
- <maxHistory>15maxHistory>
- rollingPolicy>
-
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <level>INFOlevel>
- <onMatch>ACCEPTonMatch>
- <onMismatch>DENYonMismatch>
- filter>
- appender>
-
-
- <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
-
- <file>${log.path}/log_warn.logfile>
-
- <encoder>
- <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
- <charset>UTF-8charset>
- encoder>
-
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.logfileNamePattern>
- <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
- <maxFileSize>100MBmaxFileSize>
- timeBasedFileNamingAndTriggeringPolicy>
-
- <maxHistory>15maxHistory>
- rollingPolicy>
-
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <level>warnlevel>
- <onMatch>ACCEPTonMatch>
- <onMismatch>DENYonMismatch>
- filter>
- appender>
-
-
-
- <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
-
- <file>${log.path}/log_error.logfile>
-
- <encoder>
- <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%npattern>
- <charset>UTF-8charset>
- encoder>
-
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.logfileNamePattern>
- <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
- <maxFileSize>100MBmaxFileSize>
- timeBasedFileNamingAndTriggeringPolicy>
-
- <maxHistory>15maxHistory>
- rollingPolicy>
-
- <filter class="ch.qos.logback.classic.filter.LevelFilter">
- <level>ERRORlevel>
- <onMatch>ACCEPTonMatch>
- <onMismatch>DENYonMismatch>
- filter>
- appender>
-
-
-
-
- <springProfile name="dev">
-
- <logger name="com.atguigu" level="INFO"/>
-
-
- <root level="INFO">
- <appender-ref ref="CONSOLE"/>
- <appender-ref ref="INFO_FILE"/>
- <appender-ref ref="WARN_FILE"/>
- <appender-ref ref="ERROR_FILE"/>
- root>
- springProfile>
-
-
-
- <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>
将错误日志输出到文件
error级别只进了log_error.log文件,不进warn和info文件,其他俩个同理
只需要俩处变化,即可实现把日志写入到文件中,如下图: