添加Swagger;引入Restful API标准;Exception归类;错误管理子系统完善;

This commit is contained in:
Saturneric 2020-03-25 15:51:06 +08:00
parent e8d91a4022
commit f4d00f349f
25 changed files with 275 additions and 139 deletions

14
pom.xml
View File

@ -144,6 +144,7 @@
<version>2.5.4</version>
</dependency>
<!-- 内存数据库 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
@ -163,6 +164,19 @@
<version>3.2.0</version>
</dependency>
<!-- Restful API 文档可视化支持 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
</dependencies>

View File

@ -1,5 +1,6 @@
package com.codesdream.ase.component.datamanager;
package com.codesdream.ase.component.api;
import com.codesdream.ase.component.datamanager.JSONParameter;
import com.codesdream.ase.component.json.respond.EmptyDataObjectRespond;
import com.codesdream.ase.component.json.respond.JSONBaseRespondObject;
import org.springframework.stereotype.Component;
@ -36,6 +37,11 @@ public class QuickJSONRespond {
return getJSONStandardRespond(404, "Not Found", info);
}
// 获得标准的JSON响应字符串返回(404状态)
public String getRespond404(String info, Object object){
return getJSONStandardRespond(404, "Not Found", info, object);
}
// 获得标准的JSON响应字符串返回(500状态)
public String getRespond500(String info){
return getJSONStandardRespond(500, "Internal Server Error", info);
@ -76,6 +82,11 @@ public class QuickJSONRespond {
return getJSONStandardRespond(400, "Bad Request", info);
}
// 获得标准的JSON响应字符串返回(404状态)
public String getRespond400(String info, Object object){
return getJSONStandardRespond(400, "Bad Request", info, object);
}
// 获得标准的JSON响应字符串返回(400状态)
public String getRespond409(String info){
return getJSONStandardRespond(409, "Conflict", info);

View File

@ -1,8 +1,6 @@
package com.codesdream.ase.component.auth;
import com.codesdream.ase.component.datamanager.JSONParameter;
import com.codesdream.ase.component.datamanager.QuickJSONRespond;
import com.codesdream.ase.component.json.respond.UserLoginCheckerJSONRespond;
import com.codesdream.ase.component.api.QuickJSONRespond;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;

View File

@ -1,16 +1,12 @@
package com.codesdream.ase.component.auth;
import com.codesdream.ase.component.datamanager.JSONParameter;
import com.codesdream.ase.component.datamanager.QuickJSONRespond;
import com.codesdream.ase.component.json.respond.JSONBaseRespondObject;
import com.codesdream.ase.component.json.respond.UserLoginCheckerJSONRespond;
import com.codesdream.ase.component.api.QuickJSONRespond;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

View File

@ -1,16 +1,13 @@
package com.codesdream.ase.component.auth;
import com.codesdream.ase.component.datamanager.JSONParameter;
import com.codesdream.ase.component.datamanager.QuickJSONRespond;
import com.codesdream.ase.component.api.QuickJSONRespond;
import com.codesdream.ase.component.json.respond.ErrorInfoJSONRespond;
import com.codesdream.ase.component.json.respond.UserLoginCheckerJSONRespond;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

View File

@ -1,8 +1,6 @@
package com.codesdream.ase.component.auth;
import com.codesdream.ase.component.auth.JSONTokenAuthenticationToken;
import com.codesdream.ase.component.datamanager.JSONParameter;
import com.codesdream.ase.component.datamanager.QuickJSONRespond;
import com.codesdream.ase.component.api.QuickJSONRespond;
import com.codesdream.ase.component.json.respond.UserLoginCheckerJSONRespond;
import com.codesdream.ase.model.permission.User;
@ -19,7 +17,6 @@ import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Optional;

View File

@ -1,6 +1,6 @@
package com.codesdream.ase.component.datamanager;
import com.codesdream.ase.exception.DataFileNotFoundException;
import com.codesdream.ase.exception.notfound.DataFileNotFoundException;
import com.codesdream.ase.exception.DataIOException;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;

View File

@ -2,6 +2,7 @@ package com.codesdream.ase.component.datamanager;
import com.codesdream.ase.exception.*;
import com.codesdream.ase.exception.notfound.DataFileNotFoundException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;

View File

@ -0,0 +1,41 @@
package com.codesdream.ase.component.json.model;
import com.codesdream.ase.model.permission.Tag;
import com.codesdream.ase.model.permission.User;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import net.bytebuddy.implementation.bind.annotation.DefaultMethod;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Data
@ApiModel("标签")
public class JsonableTag {
@ApiModelProperty(value = "标签id")
private Integer id = null;
@ApiModelProperty(value = "标签名", example = "系统管理员")
private String name;
@ApiModelProperty(value = "标签说明", example = "该系统的管理员")
private String description;
@ApiModelProperty(value = "用户列表", hidden = true)
private Set<Integer> users = new HashSet<>();
public JsonableTag(){
}
public JsonableTag(Tag tag){
this.id = tag.getId();
this.name = tag.getName();
this.description = tag.getDescription();
// 构建用户的ID列表
for(User user : tag.getUsers()) {
users.add(user.getId());
}
}
}

View File

@ -0,0 +1,6 @@
package com.codesdream.ase.component.json.model;
public class JsonableUidGetter {
private String checkType;
private String username;
}

View File

@ -0,0 +1,57 @@
package com.codesdream.ase.configure;
import com.google.common.collect.Sets;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.parameters.P;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Configuration
@EnableSwagger2
public class ASESwaggerConfigure {
@Bean
public Docket createRestApi() {
List<Parameter> pars = new ArrayList<Parameter>();
pars.add(new ParameterBuilder().name("username").description("真实用户名").hidden(true).order(1)
.modelRef(new ModelRef("string")).parameterType("header")
.required(false).defaultValue("u_id_88883b9e023c8824310760d8bb8b6542e5a3f16a0d67253214e01ee7ab0e96a1").build());
pars.add(new ParameterBuilder().name("signed").description("客户端签名").hidden(true).order(2)
.modelRef(new ModelRef("string")).parameterType("header")
.required(false).defaultValue("6d4923fca4dcb51f67b85e54a23a8d763d9e02af").build());
pars.add(new ParameterBuilder().name("timestamp").description("时间戳").hidden(true).order(3)
.modelRef(new ModelRef("string")).parameterType("header")
.required(false).defaultValue(Long.toString(new Date().getTime())).build());
return new Docket(DocumentationType.SWAGGER_2)
.protocols(Sets.newHashSet("http"))
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.codesdream.ase.controller"))
.paths(PathSelectors.any())
.build()
.globalOperationParameters(pars);
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("全员育人管理系统后端接口定义")
.version("0.0.1")
.description("用于对后端接口进行说明")
.build();
}
}

View File

@ -87,7 +87,13 @@ public class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter {
"/forget/**",
"/not_found/**",
"/error/**",
"/login/**");
"/login/**",
"/swagger-ui.html",
"/webjars/**",
"/swagger-resources/**",
"/v2/api-docs",
"/configuration/ui",
"/configuration/security");
}
//注册自定义的UsernamePasswordAuthenticationFilter

View File

@ -1,7 +1,11 @@
package com.codesdream.ase.controller;
import com.codesdream.ase.component.api.QuickJSONRespond;
import com.codesdream.ase.component.error.ErrorResponse;
import com.codesdream.ase.component.json.respond.ErrorInfoJSONRespond;
import com.codesdream.ase.exception.notfound.NotFoundException;
import com.sun.xml.bind.v2.model.annotation.Quick;
import org.apache.poi.openxml4j.opc.internal.ContentType;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationServiceException;
@ -11,21 +15,39 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@RestControllerAdvice
public class ASEControllerAdvice {
@ExceptionHandler(value = {RuntimeException.class})
public final Object handleRuntimeException(RuntimeException e, WebRequest webRequest){
@Resource
private QuickJSONRespond quickJSONRespond;
@ExceptionHandler(value = {NullPointerException.class})
public ResponseEntity<Object> handleBadRequest(Exception ex) {
String json = quickJSONRespond.getRespond400(null, getJSONRespondObject(ex));
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(json);
}
@ExceptionHandler(value = {NotFoundException.class})
public ResponseEntity<Object> handleNotFound(Exception ex) {
String json = quickJSONRespond.getRespond404(null, getJSONRespondObject(ex));
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(json);
}
private Object getJSONRespondObject(Exception ex){
ErrorInfoJSONRespond errorInfoJSONRespond = new ErrorInfoJSONRespond();
errorInfoJSONRespond.setException(ex.getClass().getName());
errorInfoJSONRespond.setExceptionMessage(ex.getMessage());
errorInfoJSONRespond.setDate(new Date());
errorInfoJSONRespond.setExceptionMessage(e.getMessage());
errorInfoJSONRespond.setException(e.getClass().getName());
return errorInfoJSONRespond;
}
}

View File

@ -1,24 +1,16 @@
package com.codesdream.ase.controller;
import com.codesdream.ase.component.datamanager.QuickJSONRespond;
import com.codesdream.ase.component.error.ErrorResponse;
import com.codesdream.ase.component.api.QuickJSONRespond;
import com.codesdream.ase.component.json.respond.ErrorInfoJSONRespond;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.WebRequest;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Controller
public class ASEErrorController implements ErrorController {
@ -80,7 +72,7 @@ public class ASEErrorController implements ErrorController {
return quickJSONRespond.getJSONStandardRespond(
statusCode,
"Error Controller Handle",
"Internal Server Error",
null,
errorInfoJSONRespond);
}

View File

@ -2,15 +2,17 @@ package com.codesdream.ase.controller;
import com.alibaba.fastjson.JSONObject;
import com.codesdream.ase.component.datamanager.JSONParameter;
import com.codesdream.ase.component.datamanager.QuickJSONRespond;
import com.codesdream.ase.component.api.QuickJSONRespond;
import com.codesdream.ase.component.json.respond.JSONStandardFailedRespond;
import com.codesdream.ase.component.json.request.UserLoginChecker;
import com.codesdream.ase.component.json.respond.UserLoginCheckerJSONRespond;
import com.codesdream.ase.service.IAuthService;
import com.codesdream.ase.service.IUserService;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@ -25,6 +27,7 @@ import java.util.Optional;
*/
@Slf4j
@Controller
@Api(tags = "用户登录有关接口")
public class LoginController {
@Resource
@ -39,13 +42,7 @@ public class LoginController {
@Resource
private IAuthService authService;
@RequestMapping(value = "/login")
String printLogin(Model model) {
return "login";
}
@RequestMapping(value = "/login/check_exists", method = RequestMethod.POST)
@PostMapping(value = "/login/check_exists")
@ResponseBody
String checkExists(HttpServletRequest request){

View File

@ -2,16 +2,19 @@ package com.codesdream.ase.controller;
import com.alibaba.fastjson.JSONObject;
import com.codesdream.ase.component.datamanager.JSONParameter;
import com.codesdream.ase.component.datamanager.QuickJSONRespond;
import com.codesdream.ase.component.api.QuickJSONRespond;
import com.codesdream.ase.component.json.model.JsonableTag;
import com.codesdream.ase.component.json.respond.PermissionJSONRespond;
import com.codesdream.ase.exception.notfound.TagNotFoundException;
import com.codesdream.ase.model.permission.Tag;
import com.codesdream.ase.model.permission.User;
import com.codesdream.ase.service.IUserService;
import com.codesdream.ase.service.PermissionService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
@ -21,6 +24,7 @@ import java.util.Set;
@RestController
@RequestMapping("pmt")
@Api(tags = "权限管理接口")
public class PermissionController {
@Resource
@ -36,80 +40,34 @@ public class PermissionController {
private QuickJSONRespond jsonRespond;
// 根据名字创建新的标签
@PostMapping("tag/create")
public String createTag(HttpServletRequest request){
Optional<JSONObject> jsonObjectOptional = jsonParameter.getJSONByRequest(request);
if(!jsonObjectOptional.isPresent()) return jsonRespond.getRespond400("Illegal JSON Format");
JSONObject jsonObject = jsonObjectOptional.get();
@PostMapping("tag")
@ApiOperation(value = "创建新的标签", notes = "创建标签时其ID自动分配指定ID无效")
public JsonableTag createTag(@RequestBody JsonableTag tag){
String tagName = tag.getName();
/* if(tagName == null) return jsonRespond.getRespond406("Missing Tag Name");*/
String tagName = jsonObject.getString("name");
if(tagName == null) return jsonRespond.getRespond406("Missing Tag Name");
// 检查JSON是否合法
Optional<Tag> tagOptional = permissionService.findTag(tagName);
if(tagOptional.isPresent()) return jsonRespond.getRespond409("Tag Name Already Exist");
/* if(tagOptional.isPresent()) return jsonRespond.getRespond409("Tag Name Already Exist");*/
Tag newTag = permissionService.getDefaultTag(tagName);
newTag = permissionService.save(newTag);
PermissionJSONRespond respond = new PermissionJSONRespond();
respond.setActionSuccess(true);
respond.setTagId(newTag.getId());
respond.setTagName(newTag.getName());
return jsonRespond.getRespond200(null, respond);
if(tag.getDescription() != null) {
newTag.setDescription(tag.getDescription());
}
return new JsonableTag(permissionService.save(newTag));
}
// 根据名字搜索标签的简要信息
@PostMapping("tag/search")
public String checkTag(HttpServletRequest request){
Optional<JSONObject> jsonObjectOptional = jsonParameter.getJSONByRequest(request);
if(!jsonObjectOptional.isPresent()) return jsonRespond.getRespond400("Illegal JSON Format");
JSONObject jsonObject = jsonObjectOptional.get();
String tagName = jsonObject.getString("name");
if(tagName == null) return jsonRespond.getRespond406("Problem With Tag Name");
Optional<Tag> tagOptional = permissionService.findTag(tagName);
PermissionJSONRespond respond = new PermissionJSONRespond();
respond.setActionSuccess(true);
@GetMapping("tag")
@ApiOperation("搜索标签信息")
@ApiImplicitParam(name = "name", value = "标签名")
public JsonableTag checkTag(@RequestParam(value = "name") String name){
Optional<Tag> tagOptional = permissionService.findTag(name);
if(tagOptional.isPresent()){
respond.setTagExist(true);
respond.setTagId(tagOptional.get().getId());
respond.setTagName(tagOptional.get().getName());
return new JsonableTag(tagOptional.get());
}
else respond.setTagExist(false);
return jsonRespond.getRespond200(null, respond);
}
// 由标签ID找到用户ID列表
@PostMapping("tag/get/users")
public String getUsersTag(HttpServletRequest request){
Optional<JSONObject> jsonObjectOptional = jsonParameter.getJSONByRequest(request);
if(!jsonObjectOptional.isPresent()) return jsonRespond.getRespond400("Illegal JSON Format");
JSONObject jsonObject = jsonObjectOptional.get();
Integer tagId = jsonObject.getInteger("id");
if(tagId == null) return jsonRespond.getRespond406("Problem With Tag ID");
Optional<Tag> tagOptional = permissionService.findTag(tagId);
PermissionJSONRespond respond = new PermissionJSONRespond();
respond.setActionSuccess(true);
if(tagOptional.isPresent()){
respond.setTagExist(true);
respond.setTagId(tagOptional.get().getId());
Set<Integer> userIds = new HashSet<>();
for(User user : permissionService.getUsersFromTag(tagOptional.get())) {
userIds.add(user.getId());
}
respond.setUsers(userIds);
}
else respond.setTagExist(false);
return jsonRespond.getRespond200(null, respond);
else throw new TagNotFoundException(name);
}
// 将用户添加到Tag中

View File

@ -1,7 +1,7 @@
package com.codesdream.ase.controller;
import com.codesdream.ase.component.datamanager.JSONParameter;
import com.codesdream.ase.component.datamanager.QuickJSONRespond;
import com.codesdream.ase.component.api.QuickJSONRespond;
import com.codesdream.ase.component.json.request.UserRegisterChecker;
import com.codesdream.ase.model.information.BaseStudentInfo;
import com.codesdream.ase.model.permission.User;

View File

@ -1,15 +0,0 @@
package com.codesdream.ase.exception;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class DataFileNotFoundException extends RuntimeException {
private String path;
public DataFileNotFoundException(String filePath){
super();
this.path = filePath;
}
}

View File

@ -0,0 +1,15 @@
package com.codesdream.ase.exception.notfound;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class DataFileNotFoundException extends NotFoundException {
private String path;
public DataFileNotFoundException(String msg){
super(msg);
this.path = msg;
}
}

View File

@ -0,0 +1,12 @@
package com.codesdream.ase.exception.notfound;
public class NotFoundException extends RuntimeException {
public NotFoundException(String msg){
super(msg);
}
public NotFoundException(){
super();
}
}

View File

@ -0,0 +1,11 @@
package com.codesdream.ase.exception.notfound;
public class TagNotFoundException extends NotFoundException {
String tagName;
public TagNotFoundException(String tagName){
super(tagName);
this.tagName = tagName;
}
}

View File

@ -1,22 +1,20 @@
package com.codesdream.ase.exception;
package com.codesdream.ase.exception.notfound;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class UserNotFoundException extends RuntimeException {
public class UserNotFoundException extends NotFoundException {
Integer id;
String username;
String message;
public UserNotFoundException(Integer id, String username){
super();
this.id = id;
this.username = username;
}
public UserNotFoundException(String message){
super();
this.message = message;
public UserNotFoundException(String msg){
super(msg);
}
}

View File

@ -1,12 +1,11 @@
package com.codesdream.ase.service;
import com.codesdream.ase.component.permission.UserAuthoritiesGenerator;
import com.codesdream.ase.exception.UserNotFoundException;
import com.codesdream.ase.exception.notfound.UserNotFoundException;
import com.codesdream.ase.model.permission.User;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

View File

@ -4,7 +4,7 @@ import com.codesdream.ase.component.auth.ASEPasswordEncoder;
import com.codesdream.ase.component.auth.ASEUsernameEncoder;
import com.codesdream.ase.component.permission.UserRolesListGenerator;
import com.codesdream.ase.exception.UserInformationIllegalException;
import com.codesdream.ase.exception.UserNotFoundException;
import com.codesdream.ase.exception.notfound.UserNotFoundException;
import com.codesdream.ase.exception.UsernameAlreadyExistException;
import com.codesdream.ase.model.information.BaseStudentInfo;
import com.codesdream.ase.model.permission.User;

View File

@ -0,0 +1,23 @@
server.port=8081
spring.thymeleaf.prefix=classpath:templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML
spring.thymeleaf.encoding=UTF-8
spring.jpa.generate-ddl=false
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jooq.sql-dialect=org.hibernate.dialect.MariaDB102Dialect
spring.jpa.open-in-view=true
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
spring.datasource.url=jdbc:mariadb://localhost:3306/ase?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=#a9b9fa6422
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
server.error.whitelabel.enabled=false
logging.level.root=info
logging.level.org.springframework.security=info