| @@ -42,10 +42,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { | |||
| for (String[] user : usersGroupsAndRoles) { | |||
| List<String> authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user, 2, user.length)); | |||
| log.info("> Registering new user: " + user[0] + " with the following Authorities[" + authoritiesStrings + "]"); | |||
| inMemoryUserDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]), authoritiesStrings | |||
| .stream() | |||
| .map(SimpleGrantedAuthority::new) | |||
| .collect(Collectors.toList()))); | |||
| inMemoryUserDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]), authoritiesStrings.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()))); | |||
| } | |||
| @@ -14,7 +14,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
| @SpringBootApplication | |||
| public class SpringBootDemoActuatorApplication { | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoActuatorApplication.class, args); | |||
| } | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoActuatorApplication.class, args); | |||
| } | |||
| } | |||
| @@ -9,8 +9,8 @@ import org.springframework.test.context.junit4.SpringRunner; | |||
| @SpringBootTest | |||
| public class SpringBootDemoActuatorApplicationTests { | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| } | |||
| @@ -14,7 +14,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
| @SpringBootApplication | |||
| public class SpringBootDemoAdminClientApplication { | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoAdminClientApplication.class, args); | |||
| } | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoAdminClientApplication.class, args); | |||
| } | |||
| } | |||
| @@ -13,8 +13,8 @@ import org.springframework.web.bind.annotation.RestController; | |||
| */ | |||
| @RestController | |||
| public class IndexController { | |||
| @GetMapping(value = {"", "/"}) | |||
| public String index() { | |||
| return "This is a Spring Boot Admin Client."; | |||
| } | |||
| @GetMapping(value = {"", "/"}) | |||
| public String index() { | |||
| return "This is a Spring Boot Admin Client."; | |||
| } | |||
| } | |||
| @@ -9,8 +9,8 @@ import org.springframework.test.context.junit4.SpringRunner; | |||
| @SpringBootTest | |||
| public class SpringBootDemoAdminClientApplicationTests { | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| } | |||
| @@ -16,7 +16,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
| @SpringBootApplication | |||
| public class SpringBootDemoAdminServerApplication { | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoAdminServerApplication.class, args); | |||
| } | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoAdminServerApplication.class, args); | |||
| } | |||
| } | |||
| @@ -9,8 +9,8 @@ import org.springframework.test.context.junit4.SpringRunner; | |||
| @SpringBootTest | |||
| public class SpringBootDemoAdminServerApplicationTests { | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| } | |||
| @@ -179,9 +179,7 @@ public class CodeGenUtil { | |||
| try { | |||
| //添加到zip | |||
| zip.putNextEntry(new ZipEntry(Objects.requireNonNull(getFileName(template, tableEntity.getCaseClassName(), map | |||
| .get("package") | |||
| .toString(), map.get("moduleName").toString())))); | |||
| zip.putNextEntry(new ZipEntry(Objects.requireNonNull(getFileName(template, tableEntity.getCaseClassName(), map.get("package").toString(), map.get("moduleName").toString())))); | |||
| IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString()); | |||
| IoUtil.close(sw); | |||
| zip.closeEntry(); | |||
| @@ -78,6 +78,7 @@ public enum DatasourceHolder { | |||
| /** | |||
| * 清除动态数据源 | |||
| * | |||
| * @param id 数据源id | |||
| */ | |||
| public synchronized void removeDatasource(Long id) { | |||
| @@ -37,7 +37,7 @@ public enum DatasourceScheduler { | |||
| } | |||
| } | |||
| public void schedule(Runnable task,long delay){ | |||
| public void schedule(Runnable task, long delay) { | |||
| this.scheduler.scheduleAtFixedRate(task, delay, delay, TimeUnit.MILLISECONDS); | |||
| } | |||
| @@ -35,6 +35,7 @@ public class DynamicDataSource extends HikariDataSource { | |||
| /** | |||
| * 初始化数据源 | |||
| * | |||
| * @param id 数据源id | |||
| * @return 数据源 | |||
| */ | |||
| @@ -54,7 +54,6 @@ public class Result<T> implements Serializable { | |||
| } | |||
| /** | |||
| * 返回成功 | |||
| * | |||
| @@ -70,7 +69,7 @@ public class Result<T> implements Serializable { | |||
| * 返回成功-携带数据 | |||
| * | |||
| * @param data 响应数据 | |||
| * @param <T> 泛型标记 | |||
| * @param <T> 泛型标记 | |||
| * @return 响应信息 {@code Result} | |||
| */ | |||
| public static <T> Result<T> success(@Nullable T data) { | |||
| @@ -78,7 +77,4 @@ public class Result<T> implements Serializable { | |||
| } | |||
| } | |||
| @@ -17,51 +17,51 @@ public interface PersonService { | |||
| /** | |||
| * create Index | |||
| * | |||
| * @author fxbin | |||
| * @param index elasticsearch index name | |||
| * @author fxbin | |||
| */ | |||
| void createIndex(String index); | |||
| /** | |||
| * delete Index | |||
| * | |||
| * @author fxbin | |||
| * @param index elasticsearch index name | |||
| * @author fxbin | |||
| */ | |||
| void deleteIndex(String index); | |||
| /** | |||
| * insert document source | |||
| * | |||
| * @author fxbin | |||
| * @param index elasticsearch index name | |||
| * @param list data source | |||
| * @param list data source | |||
| * @author fxbin | |||
| */ | |||
| void insert(String index, List<Person> list); | |||
| /** | |||
| * update document source | |||
| * | |||
| * @author fxbin | |||
| * @param index elasticsearch index name | |||
| * @param list data source | |||
| * @param list data source | |||
| * @author fxbin | |||
| */ | |||
| void update(String index, List<Person> list); | |||
| /** | |||
| * delete document source | |||
| * | |||
| * @author fxbin | |||
| * @param person delete data source and allow null object | |||
| * @author fxbin | |||
| */ | |||
| void delete(String index, @Nullable Person person); | |||
| /** | |||
| * search all doc records | |||
| * | |||
| * @author fxbin | |||
| * @param index elasticsearch index name | |||
| * @return person list | |||
| * @author fxbin | |||
| */ | |||
| List<Person> searchList(String index); | |||
| @@ -2,8 +2,8 @@ package com.xkcoding.elasticsearch.service.impl; | |||
| import cn.hutool.core.bean.BeanUtil; | |||
| import com.xkcoding.elasticsearch.model.Person; | |||
| import com.xkcoding.elasticsearch.service.base.BaseElasticsearchService; | |||
| import com.xkcoding.elasticsearch.service.PersonService; | |||
| import com.xkcoding.elasticsearch.service.base.BaseElasticsearchService; | |||
| import org.elasticsearch.action.index.IndexRequest; | |||
| import org.elasticsearch.action.search.SearchResponse; | |||
| import org.elasticsearch.search.SearchHit; | |||
| @@ -9,8 +9,8 @@ import org.springframework.test.context.junit4.SpringRunner; | |||
| @SpringBootTest | |||
| public class SpringBootDemoElasticsearchApplicationTests { | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| } | |||
| @@ -92,8 +92,7 @@ public class PersonRepositoryTest extends SpringBootDemoElasticsearchApplication | |||
| */ | |||
| @Test | |||
| public void select() { | |||
| repo.findAll(Sort.by(Sort.Direction.DESC, "birthday")) | |||
| .forEach(person -> log.info("{} 生日: {}", person.getName(), DateUtil.formatDateTime(person.getBirthday()))); | |||
| repo.findAll(Sort.by(Sort.Direction.DESC, "birthday")).forEach(person -> log.info("{} 生日: {}", person.getName(), DateUtil.formatDateTime(person.getBirthday()))); | |||
| } | |||
| /** | |||
| @@ -167,8 +166,8 @@ public class PersonRepositoryTest extends SpringBootDemoElasticsearchApplication | |||
| // 1. 添加一个新的聚合,聚合类型为terms,聚合名称为country,聚合字段为age | |||
| queryBuilder.addAggregation(AggregationBuilders.terms("country").field("country") | |||
| // 2. 在国家聚合桶内进行嵌套聚合,求平均年龄 | |||
| .subAggregation(AggregationBuilders.avg("avg").field("age"))); | |||
| // 2. 在国家聚合桶内进行嵌套聚合,求平均年龄 | |||
| .subAggregation(AggregationBuilders.avg("avg").field("age"))); | |||
| log.info("【queryBuilder】= {}", JSONUtil.toJsonStr(queryBuilder.build())); | |||
| @@ -9,8 +9,8 @@ import org.springframework.test.context.junit4.SpringRunner; | |||
| @SpringBootTest | |||
| public class SpringBootDemoEmailApplicationTests { | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| } | |||
| @@ -14,7 +14,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
| @SpringBootApplication | |||
| public class SpringBootDemoExceptionHandlerApplication { | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoExceptionHandlerApplication.class, args); | |||
| } | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoExceptionHandlerApplication.class, args); | |||
| } | |||
| } | |||
| @@ -12,26 +12,26 @@ import lombok.Getter; | |||
| */ | |||
| @Getter | |||
| public enum Status { | |||
| /** | |||
| * 操作成功 | |||
| */ | |||
| OK(200, "操作成功"), | |||
| /** | |||
| * 操作成功 | |||
| */ | |||
| OK(200, "操作成功"), | |||
| /** | |||
| * 未知异常 | |||
| */ | |||
| UNKNOWN_ERROR(500, "服务器出错啦"); | |||
| /** | |||
| * 状态码 | |||
| */ | |||
| private Integer code; | |||
| /** | |||
| * 内容 | |||
| */ | |||
| private String message; | |||
| /** | |||
| * 未知异常 | |||
| */ | |||
| UNKNOWN_ERROR(500, "服务器出错啦"); | |||
| /** | |||
| * 状态码 | |||
| */ | |||
| private Integer code; | |||
| /** | |||
| * 内容 | |||
| */ | |||
| private String message; | |||
| Status(Integer code, String message) { | |||
| this.code = code; | |||
| this.message = message; | |||
| } | |||
| Status(Integer code, String message) { | |||
| this.code = code; | |||
| this.message = message; | |||
| } | |||
| } | |||
| @@ -20,14 +20,14 @@ import org.springframework.web.servlet.ModelAndView; | |||
| @Controller | |||
| public class TestController { | |||
| @GetMapping("/json") | |||
| @ResponseBody | |||
| public ApiResponse jsonException() { | |||
| throw new JsonException(Status.UNKNOWN_ERROR); | |||
| } | |||
| @GetMapping("/json") | |||
| @ResponseBody | |||
| public ApiResponse jsonException() { | |||
| throw new JsonException(Status.UNKNOWN_ERROR); | |||
| } | |||
| @GetMapping("/page") | |||
| public ModelAndView pageException() { | |||
| throw new PageException(Status.UNKNOWN_ERROR); | |||
| } | |||
| @GetMapping("/page") | |||
| public ModelAndView pageException() { | |||
| throw new PageException(Status.UNKNOWN_ERROR); | |||
| } | |||
| } | |||
| @@ -15,18 +15,18 @@ import lombok.EqualsAndHashCode; | |||
| @Data | |||
| @EqualsAndHashCode(callSuper = true) | |||
| public class BaseException extends RuntimeException { | |||
| private Integer code; | |||
| private String message; | |||
| private Integer code; | |||
| private String message; | |||
| public BaseException(Status status) { | |||
| super(status.getMessage()); | |||
| this.code = status.getCode(); | |||
| this.message = status.getMessage(); | |||
| } | |||
| public BaseException(Status status) { | |||
| super(status.getMessage()); | |||
| this.code = status.getCode(); | |||
| this.message = status.getMessage(); | |||
| } | |||
| public BaseException(Integer code, String message) { | |||
| super(message); | |||
| this.code = code; | |||
| this.message = message; | |||
| } | |||
| public BaseException(Integer code, String message) { | |||
| super(message); | |||
| this.code = code; | |||
| this.message = message; | |||
| } | |||
| } | |||
| @@ -14,11 +14,11 @@ import lombok.Getter; | |||
| @Getter | |||
| public class JsonException extends BaseException { | |||
| public JsonException(Status status) { | |||
| super(status); | |||
| } | |||
| public JsonException(Status status) { | |||
| super(status); | |||
| } | |||
| public JsonException(Integer code, String message) { | |||
| super(code, message); | |||
| } | |||
| public JsonException(Integer code, String message) { | |||
| super(code, message); | |||
| } | |||
| } | |||
| @@ -14,11 +14,11 @@ import lombok.Getter; | |||
| @Getter | |||
| public class PageException extends BaseException { | |||
| public PageException(Status status) { | |||
| super(status); | |||
| } | |||
| public PageException(Status status) { | |||
| super(status); | |||
| } | |||
| public PageException(Integer code, String message) { | |||
| super(code, message); | |||
| } | |||
| public PageException(Integer code, String message) { | |||
| super(code, message); | |||
| } | |||
| } | |||
| @@ -20,33 +20,33 @@ import org.springframework.web.servlet.ModelAndView; | |||
| @ControllerAdvice | |||
| @Slf4j | |||
| public class DemoExceptionHandler { | |||
| private static final String DEFAULT_ERROR_VIEW = "error"; | |||
| private static final String DEFAULT_ERROR_VIEW = "error"; | |||
| /** | |||
| * 统一 json 异常处理 | |||
| * | |||
| * @param exception JsonException | |||
| * @return 统一返回 json 格式 | |||
| */ | |||
| @ExceptionHandler(value = JsonException.class) | |||
| @ResponseBody | |||
| public ApiResponse jsonErrorHandler(JsonException exception) { | |||
| log.error("【JsonException】:{}", exception.getMessage()); | |||
| return ApiResponse.ofException(exception); | |||
| } | |||
| /** | |||
| * 统一 json 异常处理 | |||
| * | |||
| * @param exception JsonException | |||
| * @return 统一返回 json 格式 | |||
| */ | |||
| @ExceptionHandler(value = JsonException.class) | |||
| @ResponseBody | |||
| public ApiResponse jsonErrorHandler(JsonException exception) { | |||
| log.error("【JsonException】:{}", exception.getMessage()); | |||
| return ApiResponse.ofException(exception); | |||
| } | |||
| /** | |||
| * 统一 页面 异常处理 | |||
| * | |||
| * @param exception PageException | |||
| * @return 统一跳转到异常页面 | |||
| */ | |||
| @ExceptionHandler(value = PageException.class) | |||
| public ModelAndView pageErrorHandler(PageException exception) { | |||
| log.error("【DemoPageException】:{}", exception.getMessage()); | |||
| ModelAndView view = new ModelAndView(); | |||
| view.addObject("message", exception.getMessage()); | |||
| view.setViewName(DEFAULT_ERROR_VIEW); | |||
| return view; | |||
| } | |||
| /** | |||
| * 统一 页面 异常处理 | |||
| * | |||
| * @param exception PageException | |||
| * @return 统一跳转到异常页面 | |||
| */ | |||
| @ExceptionHandler(value = PageException.class) | |||
| public ModelAndView pageErrorHandler(PageException exception) { | |||
| log.error("【DemoPageException】:{}", exception.getMessage()); | |||
| ModelAndView view = new ModelAndView(); | |||
| view.addObject("message", exception.getMessage()); | |||
| view.setViewName(DEFAULT_ERROR_VIEW); | |||
| return view; | |||
| } | |||
| } | |||
| @@ -14,114 +14,114 @@ import lombok.Data; | |||
| */ | |||
| @Data | |||
| public class ApiResponse { | |||
| /** | |||
| * 状态码 | |||
| */ | |||
| private Integer code; | |||
| /** | |||
| * 状态码 | |||
| */ | |||
| private Integer code; | |||
| /** | |||
| * 返回内容 | |||
| */ | |||
| private String message; | |||
| /** | |||
| * 返回内容 | |||
| */ | |||
| private String message; | |||
| /** | |||
| * 返回数据 | |||
| */ | |||
| private Object data; | |||
| /** | |||
| * 返回数据 | |||
| */ | |||
| private Object data; | |||
| /** | |||
| * 无参构造函数 | |||
| */ | |||
| private ApiResponse() { | |||
| /** | |||
| * 无参构造函数 | |||
| */ | |||
| private ApiResponse() { | |||
| } | |||
| } | |||
| /** | |||
| * 全参构造函数 | |||
| * | |||
| * @param code 状态码 | |||
| * @param message 返回内容 | |||
| * @param data 返回数据 | |||
| */ | |||
| private ApiResponse(Integer code, String message, Object data) { | |||
| this.code = code; | |||
| this.message = message; | |||
| this.data = data; | |||
| } | |||
| /** | |||
| * 全参构造函数 | |||
| * | |||
| * @param code 状态码 | |||
| * @param message 返回内容 | |||
| * @param data 返回数据 | |||
| */ | |||
| private ApiResponse(Integer code, String message, Object data) { | |||
| this.code = code; | |||
| this.message = message; | |||
| this.data = data; | |||
| } | |||
| /** | |||
| * 构造一个自定义的API返回 | |||
| * | |||
| * @param code 状态码 | |||
| * @param message 返回内容 | |||
| * @param data 返回数据 | |||
| * @return ApiResponse | |||
| */ | |||
| public static ApiResponse of(Integer code, String message, Object data) { | |||
| return new ApiResponse(code, message, data); | |||
| } | |||
| /** | |||
| * 构造一个自定义的API返回 | |||
| * | |||
| * @param code 状态码 | |||
| * @param message 返回内容 | |||
| * @param data 返回数据 | |||
| * @return ApiResponse | |||
| */ | |||
| public static ApiResponse of(Integer code, String message, Object data) { | |||
| return new ApiResponse(code, message, data); | |||
| } | |||
| /** | |||
| * 构造一个成功且带数据的API返回 | |||
| * | |||
| * @param data 返回数据 | |||
| * @return ApiResponse | |||
| */ | |||
| public static ApiResponse ofSuccess(Object data) { | |||
| return ofStatus(Status.OK, data); | |||
| } | |||
| /** | |||
| * 构造一个成功且带数据的API返回 | |||
| * | |||
| * @param data 返回数据 | |||
| * @return ApiResponse | |||
| */ | |||
| public static ApiResponse ofSuccess(Object data) { | |||
| return ofStatus(Status.OK, data); | |||
| } | |||
| /** | |||
| * 构造一个成功且自定义消息的API返回 | |||
| * | |||
| * @param message 返回内容 | |||
| * @return ApiResponse | |||
| */ | |||
| public static ApiResponse ofMessage(String message) { | |||
| return of(Status.OK.getCode(), message, null); | |||
| } | |||
| /** | |||
| * 构造一个成功且自定义消息的API返回 | |||
| * | |||
| * @param message 返回内容 | |||
| * @return ApiResponse | |||
| */ | |||
| public static ApiResponse ofMessage(String message) { | |||
| return of(Status.OK.getCode(), message, null); | |||
| } | |||
| /** | |||
| * 构造一个有状态的API返回 | |||
| * | |||
| * @param status 状态 {@link Status} | |||
| * @return ApiResponse | |||
| */ | |||
| public static ApiResponse ofStatus(Status status) { | |||
| return ofStatus(status, null); | |||
| } | |||
| /** | |||
| * 构造一个有状态的API返回 | |||
| * | |||
| * @param status 状态 {@link Status} | |||
| * @return ApiResponse | |||
| */ | |||
| public static ApiResponse ofStatus(Status status) { | |||
| return ofStatus(status, null); | |||
| } | |||
| /** | |||
| * 构造一个有状态且带数据的API返回 | |||
| * | |||
| * @param status 状态 {@link Status} | |||
| * @param data 返回数据 | |||
| * @return ApiResponse | |||
| */ | |||
| public static ApiResponse ofStatus(Status status, Object data) { | |||
| return of(status.getCode(), status.getMessage(), data); | |||
| } | |||
| /** | |||
| * 构造一个有状态且带数据的API返回 | |||
| * | |||
| * @param status 状态 {@link Status} | |||
| * @param data 返回数据 | |||
| * @return ApiResponse | |||
| */ | |||
| public static ApiResponse ofStatus(Status status, Object data) { | |||
| return of(status.getCode(), status.getMessage(), data); | |||
| } | |||
| /** | |||
| * 构造一个异常且带数据的API返回 | |||
| * | |||
| * @param t 异常 | |||
| * @param data 返回数据 | |||
| * @param <T> {@link BaseException} 的子类 | |||
| * @return ApiResponse | |||
| */ | |||
| public static <T extends BaseException> ApiResponse ofException(T t, Object data) { | |||
| return of(t.getCode(), t.getMessage(), data); | |||
| } | |||
| /** | |||
| * 构造一个异常且带数据的API返回 | |||
| * | |||
| * @param t 异常 | |||
| * @param data 返回数据 | |||
| * @param <T> {@link BaseException} 的子类 | |||
| * @return ApiResponse | |||
| */ | |||
| public static <T extends BaseException> ApiResponse ofException(T t, Object data) { | |||
| return of(t.getCode(), t.getMessage(), data); | |||
| } | |||
| /** | |||
| * 构造一个异常且带数据的API返回 | |||
| * | |||
| * @param t 异常 | |||
| * @param <T> {@link BaseException} 的子类 | |||
| * @return ApiResponse | |||
| */ | |||
| public static <T extends BaseException> ApiResponse ofException(T t) { | |||
| return ofException(t, null); | |||
| } | |||
| /** | |||
| * 构造一个异常且带数据的API返回 | |||
| * | |||
| * @param t 异常 | |||
| * @param <T> {@link BaseException} 的子类 | |||
| * @return ApiResponse | |||
| */ | |||
| public static <T extends BaseException> ApiResponse ofException(T t) { | |||
| return ofException(t, null); | |||
| } | |||
| } | |||
| @@ -9,8 +9,8 @@ import org.springframework.test.context.junit4.SpringRunner; | |||
| @SpringBootTest | |||
| public class SpringBootDemoExceptionHandlerApplicationTests { | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| } | |||
| @@ -1,20 +1,18 @@ | |||
| package com.xkcoding; | |||
| import static org.junit.Assert.assertTrue; | |||
| import org.junit.Test; | |||
| import static org.junit.Assert.assertTrue; | |||
| /** | |||
| * Unit test for simple App. | |||
| */ | |||
| public class AppTest | |||
| { | |||
| public class AppTest { | |||
| /** | |||
| * Rigorous Test :-) | |||
| */ | |||
| @Test | |||
| public void shouldAnswerWithTrue() | |||
| { | |||
| assertTrue( true ); | |||
| public void shouldAnswerWithTrue() { | |||
| assertTrue(true); | |||
| } | |||
| } | |||
| @@ -19,21 +19,21 @@ import org.springframework.web.bind.annotation.RestController; | |||
| @RestController | |||
| public class SpringBootDemoHelloworldApplication { | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoHelloworldApplication.class, args); | |||
| } | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoHelloworldApplication.class, args); | |||
| } | |||
| /** | |||
| * Hello,World | |||
| * | |||
| * @param who 参数,非必须 | |||
| * @return Hello, ${who} | |||
| */ | |||
| @GetMapping("/hello") | |||
| public String sayHello(@RequestParam(required = false, name = "who") String who) { | |||
| if (StrUtil.isBlank(who)) { | |||
| who = "World"; | |||
| } | |||
| return StrUtil.format("Hello, {}!", who); | |||
| } | |||
| /** | |||
| * Hello,World | |||
| * | |||
| * @param who 参数,非必须 | |||
| * @return Hello, ${who} | |||
| */ | |||
| @GetMapping("/hello") | |||
| public String sayHello(@RequestParam(required = false, name = "who") String who) { | |||
| if (StrUtil.isBlank(who)) { | |||
| who = "World"; | |||
| } | |||
| return StrUtil.format("Hello, {}!", who); | |||
| } | |||
| } | |||
| @@ -9,8 +9,8 @@ import org.springframework.test.context.junit4.SpringRunner; | |||
| @SpringBootTest | |||
| public class SpringBootDemoHelloworldApplicationTests { | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| } | |||
| @@ -1,5 +1,5 @@ | |||
| <!DOCTYPE html> | |||
| <html lang="en" xmlns:th="http://www.thymeleaf.org"> | |||
| <html lang="en"> | |||
| <head> | |||
| <meta charset="UTF-8"> | |||
| <title>spring boot demo https</title> | |||
| @@ -54,7 +54,6 @@ public class Result<T> implements Serializable { | |||
| } | |||
| /** | |||
| * 返回成功 | |||
| * | |||
| @@ -70,7 +69,7 @@ public class Result<T> implements Serializable { | |||
| * 返回成功-携带数据 | |||
| * | |||
| * @param data 响应数据 | |||
| * @param <T> 泛型标记 | |||
| * @param <T> 泛型标记 | |||
| * @return 响应信息 {@code Result} | |||
| */ | |||
| public static <T> Result<T> success(@Nullable T data) { | |||
| @@ -78,7 +77,4 @@ public class Result<T> implements Serializable { | |||
| } | |||
| } | |||
| @@ -17,10 +17,7 @@ import java.io.Serializable; | |||
| * @since 2019-08-26 0:51 | |||
| */ | |||
| @Data | |||
| @Entry( | |||
| base = "ou=people", | |||
| objectClasses = {"posixAccount", "inetOrgPerson", "top"} | |||
| ) | |||
| @Entry(base = "ou=people", objectClasses = {"posixAccount", "inetOrgPerson", "top"}) | |||
| public class Person implements Serializable { | |||
| private static final long serialVersionUID = -7946768337975852352L; | |||
| @@ -14,7 +14,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
| @SpringBootApplication | |||
| public class SpringBootDemoLogAopApplication { | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoLogAopApplication.class, args); | |||
| } | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoLogAopApplication.class, args); | |||
| } | |||
| } | |||
| @@ -26,65 +26,65 @@ import java.util.Objects; | |||
| @Component | |||
| @Slf4j | |||
| public class AopLog { | |||
| private static final String START_TIME = "request-start"; | |||
| private static final String START_TIME = "request-start"; | |||
| /** | |||
| * 切入点 | |||
| */ | |||
| @Pointcut("execution(public * com.xkcoding.log.aop.controller.*Controller.*(..))") | |||
| public void log() { | |||
| /** | |||
| * 切入点 | |||
| */ | |||
| @Pointcut("execution(public * com.xkcoding.log.aop.controller.*Controller.*(..))") | |||
| public void log() { | |||
| } | |||
| } | |||
| /** | |||
| * 前置操作 | |||
| * | |||
| * @param point 切入点 | |||
| */ | |||
| @Before("log()") | |||
| public void beforeLog(JoinPoint point) { | |||
| ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); | |||
| /** | |||
| * 前置操作 | |||
| * | |||
| * @param point 切入点 | |||
| */ | |||
| @Before("log()") | |||
| public void beforeLog(JoinPoint point) { | |||
| ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); | |||
| HttpServletRequest request = Objects.requireNonNull(attributes).getRequest(); | |||
| HttpServletRequest request = Objects.requireNonNull(attributes).getRequest(); | |||
| log.info("【请求 URL】:{}", request.getRequestURL()); | |||
| log.info("【请求 IP】:{}", request.getRemoteAddr()); | |||
| log.info("【请求类名】:{},【请求方法名】:{}", point.getSignature().getDeclaringTypeName(), point.getSignature().getName()); | |||
| log.info("【请求 URL】:{}", request.getRequestURL()); | |||
| log.info("【请求 IP】:{}", request.getRemoteAddr()); | |||
| log.info("【请求类名】:{},【请求方法名】:{}", point.getSignature().getDeclaringTypeName(), point.getSignature().getName()); | |||
| Map<String, String[]> parameterMap = request.getParameterMap(); | |||
| log.info("【请求参数】:{},", JSONUtil.toJsonStr(parameterMap)); | |||
| Long start = System.currentTimeMillis(); | |||
| request.setAttribute(START_TIME, start); | |||
| } | |||
| Map<String, String[]> parameterMap = request.getParameterMap(); | |||
| log.info("【请求参数】:{},", JSONUtil.toJsonStr(parameterMap)); | |||
| Long start = System.currentTimeMillis(); | |||
| request.setAttribute(START_TIME, start); | |||
| } | |||
| /** | |||
| * 环绕操作 | |||
| * | |||
| * @param point 切入点 | |||
| * @return 原方法返回值 | |||
| * @throws Throwable 异常信息 | |||
| */ | |||
| @Around("log()") | |||
| public Object aroundLog(ProceedingJoinPoint point) throws Throwable { | |||
| Object result = point.proceed(); | |||
| log.info("【返回值】:{}", JSONUtil.toJsonStr(result)); | |||
| return result; | |||
| } | |||
| /** | |||
| * 环绕操作 | |||
| * | |||
| * @param point 切入点 | |||
| * @return 原方法返回值 | |||
| * @throws Throwable 异常信息 | |||
| */ | |||
| @Around("log()") | |||
| public Object aroundLog(ProceedingJoinPoint point) throws Throwable { | |||
| Object result = point.proceed(); | |||
| log.info("【返回值】:{}", JSONUtil.toJsonStr(result)); | |||
| return result; | |||
| } | |||
| /** | |||
| * 后置操作 | |||
| */ | |||
| @AfterReturning("log()") | |||
| public void afterReturning() { | |||
| ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); | |||
| HttpServletRequest request = Objects.requireNonNull(attributes).getRequest(); | |||
| /** | |||
| * 后置操作 | |||
| */ | |||
| @AfterReturning("log()") | |||
| public void afterReturning() { | |||
| ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); | |||
| HttpServletRequest request = Objects.requireNonNull(attributes).getRequest(); | |||
| Long start = (Long) request.getAttribute(START_TIME); | |||
| Long end = System.currentTimeMillis(); | |||
| log.info("【请求耗时】:{}毫秒", end - start); | |||
| Long start = (Long) request.getAttribute(START_TIME); | |||
| Long end = System.currentTimeMillis(); | |||
| log.info("【请求耗时】:{}毫秒", end - start); | |||
| String header = request.getHeader("User-Agent"); | |||
| UserAgent userAgent = UserAgent.parseUserAgentString(header); | |||
| log.info("【浏览器类型】:{},【操作系统】:{},【原始User-Agent】:{}", userAgent.getBrowser().toString(), userAgent.getOperatingSystem().toString(), header); | |||
| } | |||
| String header = request.getHeader("User-Agent"); | |||
| UserAgent userAgent = UserAgent.parseUserAgentString(header); | |||
| log.info("【浏览器类型】:{},【操作系统】:{},【原始User-Agent】:{}", userAgent.getBrowser().toString(), userAgent.getOperatingSystem().toString(), header); | |||
| } | |||
| } | |||
| @@ -16,15 +16,15 @@ import org.springframework.web.bind.annotation.RestController; | |||
| @RestController | |||
| public class TestController { | |||
| /** | |||
| * 测试方法 | |||
| * | |||
| * @param who 测试参数 | |||
| * @return {@link Dict} | |||
| */ | |||
| @GetMapping("/test") | |||
| public Dict test(String who) { | |||
| return Dict.create().set("who", StrUtil.isBlank(who) ? "me" : who); | |||
| } | |||
| /** | |||
| * 测试方法 | |||
| * | |||
| * @param who 测试参数 | |||
| * @return {@link Dict} | |||
| */ | |||
| @GetMapping("/test") | |||
| public Dict test(String who) { | |||
| return Dict.create().set("who", StrUtil.isBlank(who) ? "me" : who); | |||
| } | |||
| } | |||
| @@ -9,8 +9,8 @@ import org.springframework.test.context.junit4.SpringRunner; | |||
| @SpringBootTest | |||
| public class SpringBootDemoLogAopApplicationTests { | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| } | |||
| @@ -17,19 +17,19 @@ import org.springframework.context.ConfigurableApplicationContext; | |||
| @Slf4j | |||
| public class SpringBootDemoLogbackApplication { | |||
| public static void main(String[] args) { | |||
| ConfigurableApplicationContext context = SpringApplication.run(SpringBootDemoLogbackApplication.class, args); | |||
| int length = context.getBeanDefinitionNames().length; | |||
| log.trace("Spring boot启动初始化了 {} 个 Bean", length); | |||
| log.debug("Spring boot启动初始化了 {} 个 Bean", length); | |||
| log.info("Spring boot启动初始化了 {} 个 Bean", length); | |||
| log.warn("Spring boot启动初始化了 {} 个 Bean", length); | |||
| log.error("Spring boot启动初始化了 {} 个 Bean", length); | |||
| try { | |||
| int i = 0; | |||
| int j = 1 / i; | |||
| } catch (Exception e) { | |||
| log.error("【SpringBootDemoLogbackApplication】启动异常:", e); | |||
| } | |||
| } | |||
| public static void main(String[] args) { | |||
| ConfigurableApplicationContext context = SpringApplication.run(SpringBootDemoLogbackApplication.class, args); | |||
| int length = context.getBeanDefinitionNames().length; | |||
| log.trace("Spring boot启动初始化了 {} 个 Bean", length); | |||
| log.debug("Spring boot启动初始化了 {} 个 Bean", length); | |||
| log.info("Spring boot启动初始化了 {} 个 Bean", length); | |||
| log.warn("Spring boot启动初始化了 {} 个 Bean", length); | |||
| log.error("Spring boot启动初始化了 {} 个 Bean", length); | |||
| try { | |||
| int i = 0; | |||
| int j = 1 / i; | |||
| } catch (Exception e) { | |||
| log.error("【SpringBootDemoLogbackApplication】启动异常:", e); | |||
| } | |||
| } | |||
| } | |||
| @@ -9,8 +9,8 @@ import org.springframework.test.context.junit4.SpringRunner; | |||
| @SpringBootTest | |||
| public class SpringBootDemoLogbackApplicationTests { | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| } | |||
| @@ -45,8 +45,7 @@ public class ArticleRepositoryTest extends SpringBootDemoMongodbApplicationTests | |||
| */ | |||
| @Test | |||
| public void testSave() { | |||
| Article article = new Article(1L, RandomUtil.randomString(20), RandomUtil.randomString(150), DateUtil.date(), DateUtil | |||
| .date(), 0L, 0L); | |||
| Article article = new Article(1L, RandomUtil.randomString(20), RandomUtil.randomString(150), DateUtil.date(), DateUtil.date(), 0L, 0L); | |||
| articleRepo.save(article); | |||
| log.info("【article】= {}", JSONUtil.toJsonStr(article)); | |||
| } | |||
| @@ -58,14 +57,11 @@ public class ArticleRepositoryTest extends SpringBootDemoMongodbApplicationTests | |||
| public void testSaveList() { | |||
| List<Article> articles = Lists.newArrayList(); | |||
| for (int i = 0; i < 10; i++) { | |||
| articles.add(new Article(snowflake.nextId(), RandomUtil.randomString(20), RandomUtil.randomString(150), DateUtil | |||
| .date(), DateUtil.date(), 0L, 0L)); | |||
| articles.add(new Article(snowflake.nextId(), RandomUtil.randomString(20), RandomUtil.randomString(150), DateUtil.date(), DateUtil.date(), 0L, 0L)); | |||
| } | |||
| articleRepo.saveAll(articles); | |||
| log.info("【articles】= {}", JSONUtil.toJsonStr(articles.stream() | |||
| .map(Article::getId) | |||
| .collect(Collectors.toList()))); | |||
| log.info("【articles】= {}", JSONUtil.toJsonStr(articles.stream().map(Article::getId).collect(Collectors.toList()))); | |||
| } | |||
| /** | |||
| @@ -118,9 +114,7 @@ public class ArticleRepositoryTest extends SpringBootDemoMongodbApplicationTests | |||
| update.inc("visits", 1L); | |||
| mongoTemplate.updateFirst(query, update, "article"); | |||
| articleRepo.findById(1L) | |||
| .ifPresent(article -> log.info("【标题】= {}【点赞数】= {}【访客数】= {}", article.getTitle(), article.getThumbUp(), article | |||
| .getVisits())); | |||
| articleRepo.findById(1L).ifPresent(article -> log.info("【标题】= {}【点赞数】= {}【访客数】= {}", article.getTitle(), article.getThumbUp(), article.getVisits())); | |||
| } | |||
| /** | |||
| @@ -133,10 +127,7 @@ public class ArticleRepositoryTest extends SpringBootDemoMongodbApplicationTests | |||
| Page<Article> all = articleRepo.findAll(pageRequest); | |||
| log.info("【总页数】= {}", all.getTotalPages()); | |||
| log.info("【总条数】= {}", all.getTotalElements()); | |||
| log.info("【当前页数据】= {}", JSONUtil.toJsonStr(all.getContent() | |||
| .stream() | |||
| .map(article -> "文章标题:" + article.getTitle() + "点赞数:" + article.getThumbUp() + "更新时间:" + article.getUpdateTime()) | |||
| .collect(Collectors.toList()))); | |||
| log.info("【当前页数据】= {}", JSONUtil.toJsonStr(all.getContent().stream().map(article -> "文章标题:" + article.getTitle() + "点赞数:" + article.getThumbUp() + "更新时间:" + article.getUpdateTime()).collect(Collectors.toList()))); | |||
| } | |||
| /** | |||
| @@ -61,18 +61,15 @@ public class SpringBootDemoMqRabbitmqApplicationTests { | |||
| */ | |||
| @Test | |||
| public void sendDelay() { | |||
| rabbitTemplate.convertAndSend(RabbitConsts.DELAY_MODE_QUEUE, RabbitConsts.DELAY_QUEUE, new MessageStruct("delay message, delay 5s, " + DateUtil | |||
| .date()), message -> { | |||
| rabbitTemplate.convertAndSend(RabbitConsts.DELAY_MODE_QUEUE, RabbitConsts.DELAY_QUEUE, new MessageStruct("delay message, delay 5s, " + DateUtil.date()), message -> { | |||
| message.getMessageProperties().setHeader("x-delay", 5000); | |||
| return message; | |||
| }); | |||
| rabbitTemplate.convertAndSend(RabbitConsts.DELAY_MODE_QUEUE, RabbitConsts.DELAY_QUEUE, new MessageStruct("delay message, delay 2s, " + DateUtil | |||
| .date()), message -> { | |||
| rabbitTemplate.convertAndSend(RabbitConsts.DELAY_MODE_QUEUE, RabbitConsts.DELAY_QUEUE, new MessageStruct("delay message, delay 2s, " + DateUtil.date()), message -> { | |||
| message.getMessageProperties().setHeader("x-delay", 2000); | |||
| return message; | |||
| }); | |||
| rabbitTemplate.convertAndSend(RabbitConsts.DELAY_MODE_QUEUE, RabbitConsts.DELAY_QUEUE, new MessageStruct("delay message, delay 8s, " + DateUtil | |||
| .date()), message -> { | |||
| rabbitTemplate.convertAndSend(RabbitConsts.DELAY_MODE_QUEUE, RabbitConsts.DELAY_QUEUE, new MessageStruct("delay message, delay 8s, " + DateUtil.date()), message -> { | |||
| message.getMessageProperties().setHeader("x-delay", 8000); | |||
| return message; | |||
| }); | |||
| @@ -28,12 +28,12 @@ import javax.sql.DataSource; | |||
| @Configuration | |||
| @EnableTransactionManagement | |||
| @EnableJpaRepositories( | |||
| // repository包名 | |||
| basePackages = PrimaryJpaConfig.REPOSITORY_PACKAGE, | |||
| // 实体管理bean名称 | |||
| entityManagerFactoryRef = "primaryEntityManagerFactory", | |||
| // 事务管理bean名称 | |||
| transactionManagerRef = "primaryTransactionManager") | |||
| // repository包名 | |||
| basePackages = PrimaryJpaConfig.REPOSITORY_PACKAGE, | |||
| // 实体管理bean名称 | |||
| entityManagerFactoryRef = "primaryEntityManagerFactory", | |||
| // 事务管理bean名称 | |||
| transactionManagerRef = "primaryTransactionManager") | |||
| public class PrimaryJpaConfig { | |||
| static final String REPOSITORY_PACKAGE = "com.xkcoding.multi.datasource.jpa.repository.primary"; | |||
| private static final String ENTITY_PACKAGE = "com.xkcoding.multi.datasource.jpa.entity.primary"; | |||
| @@ -63,14 +63,14 @@ public class PrimaryJpaConfig { | |||
| @Bean(name = "primaryEntityManagerFactory") | |||
| public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("primaryDataSource") DataSource primaryDataSource, @Qualifier("primaryJpaProperties") JpaProperties jpaProperties, EntityManagerFactoryBuilder builder) { | |||
| return builder | |||
| // 设置数据源 | |||
| .dataSource(primaryDataSource) | |||
| // 设置jpa配置 | |||
| .properties(jpaProperties.getProperties()) | |||
| // 设置实体包名 | |||
| .packages(ENTITY_PACKAGE) | |||
| // 设置持久化单元名,用于@PersistenceContext注解获取EntityManager时指定数据源 | |||
| .persistenceUnit("primaryPersistenceUnit").build(); | |||
| // 设置数据源 | |||
| .dataSource(primaryDataSource) | |||
| // 设置jpa配置 | |||
| .properties(jpaProperties.getProperties()) | |||
| // 设置实体包名 | |||
| .packages(ENTITY_PACKAGE) | |||
| // 设置持久化单元名,用于@PersistenceContext注解获取EntityManager时指定数据源 | |||
| .persistenceUnit("primaryPersistenceUnit").build(); | |||
| } | |||
| /** | |||
| @@ -27,12 +27,12 @@ import javax.sql.DataSource; | |||
| @Configuration | |||
| @EnableTransactionManagement | |||
| @EnableJpaRepositories( | |||
| // repository包名 | |||
| basePackages = SecondJpaConfig.REPOSITORY_PACKAGE, | |||
| // 实体管理bean名称 | |||
| entityManagerFactoryRef = "secondEntityManagerFactory", | |||
| // 事务管理bean名称 | |||
| transactionManagerRef = "secondTransactionManager") | |||
| // repository包名 | |||
| basePackages = SecondJpaConfig.REPOSITORY_PACKAGE, | |||
| // 实体管理bean名称 | |||
| entityManagerFactoryRef = "secondEntityManagerFactory", | |||
| // 事务管理bean名称 | |||
| transactionManagerRef = "secondTransactionManager") | |||
| public class SecondJpaConfig { | |||
| static final String REPOSITORY_PACKAGE = "com.xkcoding.multi.datasource.jpa.repository.second"; | |||
| private static final String ENTITY_PACKAGE = "com.xkcoding.multi.datasource.jpa.entity.second"; | |||
| @@ -60,14 +60,14 @@ public class SecondJpaConfig { | |||
| @Bean(name = "secondEntityManagerFactory") | |||
| public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("secondDataSource") DataSource secondDataSource, @Qualifier("secondJpaProperties") JpaProperties jpaProperties, EntityManagerFactoryBuilder builder) { | |||
| return builder | |||
| // 设置数据源 | |||
| .dataSource(secondDataSource) | |||
| // 设置jpa配置 | |||
| .properties(jpaProperties.getProperties()) | |||
| // 设置实体包名 | |||
| .packages(ENTITY_PACKAGE) | |||
| // 设置持久化单元名,用于@PersistenceContext注解获取EntityManager时指定数据源 | |||
| .persistenceUnit("secondPersistenceUnit").build(); | |||
| // 设置数据源 | |||
| .dataSource(secondDataSource) | |||
| // 设置jpa配置 | |||
| .properties(jpaProperties.getProperties()) | |||
| // 设置实体包名 | |||
| .packages(ENTITY_PACKAGE) | |||
| // 设置持久化单元名,用于@PersistenceContext注解获取EntityManager时指定数据源 | |||
| .persistenceUnit("secondPersistenceUnit").build(); | |||
| } | |||
| /** | |||
| @@ -16,7 +16,7 @@ import org.springframework.context.annotation.Configuration; | |||
| @Configuration | |||
| public class SnowflakeConfig { | |||
| @Bean | |||
| public Snowflake snowflake(){ | |||
| return IdUtil.createSnowflake(1,1); | |||
| public Snowflake snowflake() { | |||
| return IdUtil.createSnowflake(1, 1); | |||
| } | |||
| } | |||
| @@ -28,7 +28,7 @@ public class SpringBootDemoMultiDatasourceJpaApplicationTests { | |||
| @Test | |||
| public void testInsert() { | |||
| PrimaryMultiTable primary = new PrimaryMultiTable(snowflake.nextId(),"测试名称-1"); | |||
| PrimaryMultiTable primary = new PrimaryMultiTable(snowflake.nextId(), "测试名称-1"); | |||
| primaryRepo.save(primary); | |||
| SecondMultiTable second = new SecondMultiTable(); | |||
| @@ -39,7 +39,7 @@ public class SpringBootDemoMultiDatasourceJpaApplicationTests { | |||
| @Test | |||
| public void testUpdate() { | |||
| primaryRepo.findAll().forEach(primary -> { | |||
| primary.setName("修改后的"+primary.getName()); | |||
| primary.setName("修改后的" + primary.getName()); | |||
| primaryRepo.save(primary); | |||
| SecondMultiTable second = new SecondMultiTable(); | |||
| @@ -90,10 +90,8 @@ public class NeoService { | |||
| classRepo.save(seven); | |||
| // 初始化学生 | |||
| List<Student> threeClass = Lists.newArrayList(Student.of("漩涡鸣人", Lists.newArrayList(tishu, shoulijian, luoxuanwan, xianshu), seven), Student | |||
| .of("宇智波佐助", Lists.newArrayList(huanshu, zhouyin, shoulijian), seven), Student.of("春野樱", Lists.newArrayList(tishu, yiliao, shoulijian), seven)); | |||
| List<Student> sevenClass = Lists.newArrayList(Student.of("李洛克", Lists.newArrayList(tishu), three), Student.of("日向宁次", Lists | |||
| .newArrayList(tishu), three), Student.of("天天", Lists.newArrayList(tishu), three)); | |||
| List<Student> threeClass = Lists.newArrayList(Student.of("漩涡鸣人", Lists.newArrayList(tishu, shoulijian, luoxuanwan, xianshu), seven), Student.of("宇智波佐助", Lists.newArrayList(huanshu, zhouyin, shoulijian), seven), Student.of("春野樱", Lists.newArrayList(tishu, yiliao, shoulijian), seven)); | |||
| List<Student> sevenClass = Lists.newArrayList(Student.of("李洛克", Lists.newArrayList(tishu), three), Student.of("日向宁次", Lists.newArrayList(tishu), three), Student.of("天天", Lists.newArrayList(tishu), three)); | |||
| studentRepo.saveAll(threeClass); | |||
| studentRepo.saveAll(sevenClass); | |||
| @@ -155,8 +153,7 @@ public class NeoService { | |||
| List<ClassmateInfoGroupByLesson> groupByLesson = studentRepo.findByClassmateGroupByLesson(); | |||
| Map<String, List<Student>> result = Maps.newHashMap(); | |||
| groupByLesson.forEach(classmateInfoGroupByLesson -> result.put(classmateInfoGroupByLesson.getLessonName(), classmateInfoGroupByLesson | |||
| .getStudents())); | |||
| groupByLesson.forEach(classmateInfoGroupByLesson -> result.put(classmateInfoGroupByLesson.getLessonName(), classmateInfoGroupByLesson.getStudents())); | |||
| return result; | |||
| } | |||
| @@ -171,11 +168,9 @@ public class NeoService { | |||
| List<TeacherStudent> teacherStudentByLesson = studentRepo.findTeacherStudentByLesson(); | |||
| Map<String, Set<Student>> result = Maps.newHashMap(); | |||
| teacherStudentByClass.forEach(teacherStudent -> result.put(teacherStudent.getTeacherName(), Sets.newHashSet(teacherStudent | |||
| .getStudents()))); | |||
| teacherStudentByClass.forEach(teacherStudent -> result.put(teacherStudent.getTeacherName(), Sets.newHashSet(teacherStudent.getStudents()))); | |||
| teacherStudentByLesson.forEach(teacherStudent -> result.put(teacherStudent.getTeacherName(), Sets.newHashSet(teacherStudent | |||
| .getStudents()))); | |||
| teacherStudentByLesson.forEach(teacherStudent -> result.put(teacherStudent.getTeacherName(), Sets.newHashSet(teacherStudent.getStudents()))); | |||
| return result; | |||
| } | |||
| @@ -71,9 +71,7 @@ public class Neo4jTest extends SpringBootDemoNeo4jApplicationTests { | |||
| @Test | |||
| public void testFindClassmates() { | |||
| Map<String, List<Student>> classmates = neoService.findClassmatesGroupByLesson(); | |||
| classmates.forEach((k, v) -> log.info("因为一起上了【{}】这门课,成为同学关系的有:{}", k, JSONUtil.toJsonStr(v.stream() | |||
| .map(Student::getName) | |||
| .collect(Collectors.toList())))); | |||
| classmates.forEach((k, v) -> log.info("因为一起上了【{}】这门课,成为同学关系的有:{}", k, JSONUtil.toJsonStr(v.stream().map(Student::getName).collect(Collectors.toList())))); | |||
| } | |||
| /** | |||
| @@ -82,8 +80,6 @@ public class Neo4jTest extends SpringBootDemoNeo4jApplicationTests { | |||
| @Test | |||
| public void testFindTeacherStudent() { | |||
| Map<String, Set<Student>> teacherStudent = neoService.findTeacherStudent(); | |||
| teacherStudent.forEach((k, v) -> log.info("【{}】教的学生有 {}", k, JSONUtil.toJsonStr(v.stream() | |||
| .map(Student::getName) | |||
| .collect(Collectors.toList())))); | |||
| teacherStudent.forEach((k, v) -> log.info("【{}】教的学生有 {}", k, JSONUtil.toJsonStr(v.stream().map(Student::getName).collect(Collectors.toList())))); | |||
| } | |||
| } | |||
| @@ -21,11 +21,9 @@ import java.net.URLEncoder; | |||
| @Component | |||
| public class ClientLoginFailureHandler implements AuthenticationFailureHandler { | |||
| @Override | |||
| public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, | |||
| AuthenticationException exception) throws IOException { | |||
| public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException { | |||
| log.debug("Login failed!"); | |||
| response.setStatus(HttpStatus.UNAUTHORIZED.value()); | |||
| response.sendRedirect("/oauth/login?error=" | |||
| + URLEncoder.encode(exception.getLocalizedMessage(), "UTF-8")); | |||
| response.sendRedirect("/oauth/login?error=" + URLEncoder.encode(exception.getLocalizedMessage(), "UTF-8")); | |||
| } | |||
| } | |||
| @@ -31,10 +31,7 @@ public class Oauth2AuthorizationServerConfig extends AuthorizationServerConfigur | |||
| @Override | |||
| public void configure(AuthorizationServerEndpointsConfigurer endpoints) { | |||
| endpoints.authenticationManager(authenticationManager) | |||
| .userDetailsService(sysUserService) | |||
| .tokenStore(tokenStore) | |||
| .accessTokenConverter(jwtAccessTokenConverter); | |||
| endpoints.authenticationManager(authenticationManager).userDetailsService(sysUserService).tokenStore(tokenStore).accessTokenConverter(jwtAccessTokenConverter); | |||
| } | |||
| @Override | |||
| @@ -24,20 +24,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { | |||
| @Override | |||
| protected void configure(HttpSecurity http) throws Exception { | |||
| http | |||
| .formLogin() | |||
| .loginPage("/oauth/login") | |||
| .failureHandler(clientLoginFailureHandler) | |||
| .loginProcessingUrl("/authorization/form") | |||
| .and() | |||
| .logout() | |||
| .logoutUrl("/oauth/logout") | |||
| .logoutSuccessHandler(clientLogoutSuccessHandler) | |||
| .and() | |||
| .authorizeRequests() | |||
| .antMatchers("/oauth/**").permitAll() | |||
| .anyRequest() | |||
| .authenticated(); | |||
| http.formLogin().loginPage("/oauth/login").failureHandler(clientLoginFailureHandler).loginProcessingUrl("/authorization/form").and().logout().logoutUrl("/oauth/logout").logoutSuccessHandler(clientLogoutSuccessHandler).and().authorizeRequests().antMatchers("/oauth/**").permitAll().anyRequest().authenticated(); | |||
| } | |||
| /** | |||
| @@ -4,10 +4,10 @@ | |||
| * {@link com.xkcoding.oauth.config.Oauth2AuthorizationServerConfig} | |||
| * 授权服务器相关的配置,主要设置授权服务器如何读取客户端、用户信息和一些端点配置 | |||
| * 可以在这里配置更多的东西,例如端点映射,token 增强等 | |||
| * | |||
| * <p> | |||
| * {@link com.xkcoding.oauth.config.Oauth2AuthorizationTokenConfig} | |||
| * 授权服务器 token 相关的配置,主要设置 jwt、加密方式等信息 | |||
| * | |||
| * <p> | |||
| * {@link com.xkcoding.oauth.config.ClientLogoutSuccessHandler} | |||
| * 资源服务器退出以后的处理。在授权码模式中,所有的客户端都需要跳转到授权服务器进行登录 | |||
| * 当登录成功以后跳转到回调地址,如果用户需要登出,也要跳转到授权服务器这里进行登出 | |||
| @@ -15,7 +15,6 @@ | |||
| * 所以自己给登出端点加了一个 redirect_url 参数,表示登出成功以后要跳转的地址 | |||
| * 这个处理器就是来完成登出成功以后的跳转操作的。 | |||
| * | |||
| * | |||
| * @author <a href="https://echocow.cn">EchoCow</a> | |||
| * @date 2020-01-07 9:16 | |||
| */ | |||
| @@ -36,12 +36,11 @@ public class Oauth2Controller { | |||
| * 退出登录 | |||
| * | |||
| * @param redirectUrl 退出完成后的回调地址 | |||
| * @param principal 用户信息 | |||
| * @param principal 用户信息 | |||
| * @return 结果 | |||
| */ | |||
| @GetMapping("/logout") | |||
| public ModelAndView logoutView( | |||
| @RequestParam("redirect_url") String redirectUrl, Principal principal) { | |||
| public ModelAndView logoutView(@RequestParam("redirect_url") String redirectUrl, Principal principal) { | |||
| if (Objects.isNull(principal)) { | |||
| throw new ResourceAccessException("请求错误,用户尚未登录"); | |||
| } | |||
| @@ -2,7 +2,7 @@ | |||
| * 控制器。除了业务逻辑的以外,提供两个控制器来帮助完成自定义: | |||
| * {@link com.xkcoding.oauth.controller.AuthorizationController} | |||
| * 自定义的授权控制器,重新设置到我们的界面中去,不使用他的默认实现 | |||
| * | |||
| * <p> | |||
| * {@link com.xkcoding.oauth.controller.Oauth2Controller} | |||
| * 页面跳转的控制器,这里拿出来是因为真的可以做很多事。比如登录的时候携带点什么 | |||
| * 或者退出的时候携带什么标识,都可以。 | |||
| @@ -47,9 +47,6 @@ public class SysUser { | |||
| * 当前用户所有角色. | |||
| */ | |||
| @ManyToMany(fetch = FetchType.EAGER) | |||
| @JoinTable(name = "sys_user_role", | |||
| joinColumns = @JoinColumn(name = "user_id"), | |||
| inverseJoinColumns = @JoinColumn(name = "role_id") | |||
| ) | |||
| @JoinTable(name = "sys_user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id")) | |||
| private Set<SysRole> roles; | |||
| } | |||
| @@ -5,7 +5,10 @@ import com.xkcoding.oauth.repostiory.SysClientDetailsRepository; | |||
| import com.xkcoding.oauth.service.SysClientDetailsService; | |||
| import lombok.RequiredArgsConstructor; | |||
| import org.springframework.security.crypto.password.PasswordEncoder; | |||
| import org.springframework.security.oauth2.provider.*; | |||
| import org.springframework.security.oauth2.provider.ClientAlreadyExistsException; | |||
| import org.springframework.security.oauth2.provider.ClientDetails; | |||
| import org.springframework.security.oauth2.provider.ClientRegistrationException; | |||
| import org.springframework.security.oauth2.provider.NoSuchClientException; | |||
| import org.springframework.stereotype.Service; | |||
| import java.util.List; | |||
| @@ -25,14 +28,12 @@ public class SysClientDetailsServiceImpl implements SysClientDetailsService { | |||
| @Override | |||
| public ClientDetails loadClientByClientId(String id) throws ClientRegistrationException { | |||
| return sysClientDetailsRepository.findFirstByClientId(id) | |||
| .orElseThrow(() -> new ClientRegistrationException("Loading client exception.")); | |||
| return sysClientDetailsRepository.findFirstByClientId(id).orElseThrow(() -> new ClientRegistrationException("Loading client exception.")); | |||
| } | |||
| @Override | |||
| public SysClientDetails findByClientId(String clientId) { | |||
| return sysClientDetailsRepository.findFirstByClientId(clientId) | |||
| .orElseThrow(() -> new ClientRegistrationException("Loading client exception.")); | |||
| return sysClientDetailsRepository.findFirstByClientId(clientId).orElseThrow(() -> new ClientRegistrationException("Loading client exception.")); | |||
| } | |||
| @Override | |||
| @@ -46,16 +47,14 @@ public class SysClientDetailsServiceImpl implements SysClientDetailsService { | |||
| @Override | |||
| public void updateClientDetails(SysClientDetails clientDetails) throws NoSuchClientException { | |||
| SysClientDetails exist = sysClientDetailsRepository.findFirstByClientId(clientDetails.getClientId()) | |||
| .orElseThrow(() -> new NoSuchClientException("No such client!")); | |||
| SysClientDetails exist = sysClientDetailsRepository.findFirstByClientId(clientDetails.getClientId()).orElseThrow(() -> new NoSuchClientException("No such client!")); | |||
| clientDetails.setClientSecret(exist.getClientSecret()); | |||
| sysClientDetailsRepository.save(clientDetails); | |||
| } | |||
| @Override | |||
| public void updateClientSecret(String clientId, String clientSecret) throws NoSuchClientException { | |||
| SysClientDetails exist = sysClientDetailsRepository.findFirstByClientId(clientId) | |||
| .orElseThrow(() -> new NoSuchClientException("No such client!")); | |||
| SysClientDetails exist = sysClientDetailsRepository.findFirstByClientId(clientId).orElseThrow(() -> new NoSuchClientException("No such client!")); | |||
| exist.setClientSecret(passwordEncoder.encode(clientSecret)); | |||
| sysClientDetailsRepository.save(exist); | |||
| } | |||
| @@ -29,11 +29,8 @@ public class SysUserServiceImpl implements SysUserService { | |||
| @Override | |||
| public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { | |||
| SysUser sysUser = sysUserRepository.findFirstByUsername(username) | |||
| .orElseThrow(() -> new UsernameNotFoundException("User not found!")); | |||
| List<SimpleGrantedAuthority> roles = sysUser.getRoles().stream() | |||
| .map(sysRole -> new SimpleGrantedAuthority(sysRole.getName())) | |||
| .collect(Collectors.toList()); | |||
| SysUser sysUser = sysUserRepository.findFirstByUsername(username).orElseThrow(() -> new UsernameNotFoundException("User not found!")); | |||
| List<SimpleGrantedAuthority> roles = sysUser.getRoles().stream().map(sysRole -> new SimpleGrantedAuthority(sysRole.getName())).collect(Collectors.toList()); | |||
| // 在这里手动构建 UserDetails 的默认实现 | |||
| return new User(sysUser.getUsername(), sysUser.getPassword(), roles); | |||
| } | |||
| @@ -45,8 +42,7 @@ public class SysUserServiceImpl implements SysUserService { | |||
| @Override | |||
| public SysUser findById(Long id) { | |||
| return sysUserRepository.findById(id) | |||
| .orElseThrow(() -> new RuntimeException("找不到用户")); | |||
| return sysUserRepository.findById(id).orElseThrow(() -> new RuntimeException("找不到用户")); | |||
| } | |||
| @Override | |||
| @@ -46,15 +46,13 @@ public class AuthorizationCodeGrantTests { | |||
| @Test | |||
| void testCannotConnectWithoutToken() { | |||
| OAuth2RestTemplate template = new OAuth2RestTemplate(resource); | |||
| assertThrows(UserRedirectRequiredException.class, | |||
| () -> template.getForObject(getUrl("/oauth/me"), String.class)); | |||
| assertThrows(UserRedirectRequiredException.class, () -> template.getForObject(getUrl("/oauth/me"), String.class)); | |||
| } | |||
| @Test | |||
| void testAttemptedTokenAcquisitionWithNoRedirect() { | |||
| AuthorizationCodeAccessTokenProvider provider = new AuthorizationCodeAccessTokenProvider(); | |||
| assertThrows(UserRedirectRequiredException.class, | |||
| () -> provider.obtainAccessToken(resource, new DefaultAccessTokenRequest())); | |||
| assertThrows(UserRedirectRequiredException.class, () -> provider.obtainAccessToken(resource, new DefaultAccessTokenRequest())); | |||
| } | |||
| /** | |||
| @@ -80,8 +78,7 @@ public class AuthorizationCodeGrantTests { | |||
| form.add("_csrf", matcher.group(1)); | |||
| // 3. 登录授权并获取登录成功的 cookie | |||
| ResponseEntity<Void> response = authorizationServerInfo | |||
| .postForStatus("/authorization/form", headers, form); | |||
| ResponseEntity<Void> response = authorizationServerInfo.postForStatus("/authorization/form", headers, form); | |||
| assertNotNull(response); | |||
| cookie = response.getHeaders().getFirst("Set-Cookie"); | |||
| headers = new HttpHeaders(); | |||
| @@ -89,8 +86,7 @@ public class AuthorizationCodeGrantTests { | |||
| headers.setAccept(Collections.singletonList(MediaType.ALL)); | |||
| // 4. 请求到 确认授权页面 ,获取确认授权页面的 _csrf 的 value | |||
| ResponseEntity<String> confirm = authorizationServerInfo | |||
| .getForString("/oauth/authorize?response_type=code&client_id=oauth2&redirect_uri=http://example.com&scope=READ", headers); | |||
| ResponseEntity<String> confirm = authorizationServerInfo.getForString("/oauth/authorize?response_type=code&client_id=oauth2&redirect_uri=http://example.com&scope=READ", headers); | |||
| headers = confirm.getHeaders(); | |||
| // 确认过一次后,后面都会自动确认了,这里判断下是不是重定向请求 | |||
| @@ -55,8 +55,7 @@ public class AuthorizationServerInfo { | |||
| HttpHeaders actualHeaders = new HttpHeaders(); | |||
| actualHeaders.putAll(headers); | |||
| actualHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED); | |||
| return client.exchange(getUrl(path), HttpMethod.POST, | |||
| new HttpEntity<>(formData, actualHeaders), (Class<Void>) null); | |||
| return client.exchange(getUrl(path), HttpMethod.POST, new HttpEntity<>(formData, actualHeaders), (Class<Void>) null); | |||
| } | |||
| @@ -83,8 +82,7 @@ public class AuthorizationServerInfo { | |||
| } | |||
| builder.deleteCharAt(builder.length() - 1); | |||
| return client.execute(builder.toString(), HttpMethod.POST, requestCallback, | |||
| HttpMessage::getHeaders); | |||
| return client.execute(builder.toString(), HttpMethod.POST, requestCallback, HttpMessage::getHeaders); | |||
| } | |||
| private static final class NullRequestCallback implements RequestCallback { | |||
| @@ -8,7 +8,7 @@ import org.springframework.security.oauth2.common.OAuth2AccessToken; | |||
| import java.util.Arrays; | |||
| import static com.xkcoding.oauth.oauth.AuthorizationServerInfo.getUrl; | |||
| import static org.junit.jupiter.api.Assertions.*; | |||
| import static org.junit.jupiter.api.Assertions.assertNotNull; | |||
| /** | |||
| * . | |||
| @@ -8,8 +8,8 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.E | |||
| * 启动器. | |||
| * | |||
| * @author <a href="https://echocow.cn">EchoCow</a> | |||
| * @date 2020-01-09 11:38 | |||
| * @version V1.0 | |||
| * @date 2020-01-09 11:38 | |||
| */ | |||
| @EnableResourceServer | |||
| @SpringBootApplication | |||
| @@ -28,9 +28,7 @@ public class OauthResourceServerConfig extends ResourceServerConfigurerAdapter { | |||
| @Override | |||
| public void configure(ResourceServerSecurityConfigurer resources) { | |||
| resources | |||
| .tokenStore(tokenStore) | |||
| .resourceId(resourceServerProperties.getResourceId()); | |||
| resources.tokenStore(tokenStore).resourceId(resourceServerProperties.getResourceId()); | |||
| } | |||
| @Override | |||
| @@ -62,9 +62,7 @@ public class OauthResourceTokenConfig { | |||
| */ | |||
| private String getPubKey() { | |||
| // 如果本地没有密钥,就从授权服务器中获取 | |||
| return StringUtils.isEmpty(resourceServerProperties.getJwt().getKeyValue()) | |||
| ? getKeyFromAuthorizationServer() | |||
| : resourceServerProperties.getJwt().getKeyValue(); | |||
| return StringUtils.isEmpty(resourceServerProperties.getJwt().getKeyValue()) ? getKeyFromAuthorizationServer() : resourceServerProperties.getJwt().getKeyValue(); | |||
| } | |||
| /** | |||
| @@ -78,8 +76,7 @@ public class OauthResourceTokenConfig { | |||
| HttpHeaders httpHeaders = new HttpHeaders(); | |||
| httpHeaders.add(HttpHeaders.AUTHORIZATION, encodeClient()); | |||
| HttpEntity<String> requestEntity = new HttpEntity<>(null, httpHeaders); | |||
| String pubKey = new RestTemplate() | |||
| .getForObject(resourceServerProperties.getJwt().getKeyUri(), String.class, requestEntity); | |||
| String pubKey = new RestTemplate().getForObject(resourceServerProperties.getJwt().getKeyUri(), String.class, requestEntity); | |||
| try { | |||
| JSONObject body = objectMapper.readValue(pubKey, JSONObject.class); | |||
| log.info("Get Key From Authorization Server."); | |||
| @@ -96,7 +93,6 @@ public class OauthResourceTokenConfig { | |||
| * @return basic | |||
| */ | |||
| private String encodeClient() { | |||
| return "Basic " + Base64.getEncoder().encodeToString((resourceServerProperties.getClientId() | |||
| + ":" + resourceServerProperties.getClientSecret()).getBytes()); | |||
| return "Basic " + Base64.getEncoder().encodeToString((resourceServerProperties.getClientId() + ":" + resourceServerProperties.getClientSecret()).getBytes()); | |||
| } | |||
| } | |||
| @@ -32,7 +32,6 @@ public class AuthorizationTest { | |||
| @Test | |||
| void testAccessTokenWhenPassed() { | |||
| assertNotNull(oauth2RestTemplate("admin", "123456", Collections.singletonList("READ")) | |||
| .getAccessToken()); | |||
| assertNotNull(oauth2RestTemplate("admin", "123456", Collections.singletonList("READ")).getAccessToken()); | |||
| } | |||
| } | |||
| @@ -32,8 +32,7 @@ public class TestControllerTest extends AuthorizationTest { | |||
| ResponseEntity<String> response = template.exchange(URL + "/admin", GET, null, String.class); | |||
| assertEquals(HttpStatus.OK, response.getStatusCode()); | |||
| assertEquals("ADMIN", response.getBody()); | |||
| assertThrows(OAuth2AccessDeniedException.class, | |||
| () -> template.exchange(URL + "/test", GET, null, String.class)); | |||
| assertThrows(OAuth2AccessDeniedException.class, () -> template.exchange(URL + "/test", GET, null, String.class)); | |||
| } | |||
| @Test | |||
| @@ -43,8 +42,7 @@ public class TestControllerTest extends AuthorizationTest { | |||
| ResponseEntity<String> response = template.exchange(URL + "/test", GET, null, String.class); | |||
| assertEquals(HttpStatus.OK, response.getStatusCode()); | |||
| assertEquals("TEST", response.getBody()); | |||
| assertThrows(OAuth2AccessDeniedException.class, | |||
| () -> template.exchange(URL + "/admin", GET, null, String.class)); | |||
| assertThrows(OAuth2AccessDeniedException.class, () -> template.exchange(URL + "/admin", GET, null, String.class)); | |||
| } | |||
| @Test | |||
| @@ -54,8 +52,7 @@ public class TestControllerTest extends AuthorizationTest { | |||
| ResponseEntity<String> response = template.exchange(URL + "/read", GET, null, String.class); | |||
| assertEquals(HttpStatus.OK, response.getStatusCode()); | |||
| assertEquals("READ", response.getBody()); | |||
| assertThrows(OAuth2AccessDeniedException.class, | |||
| () -> template.exchange(URL + "/write", GET, null, String.class)); | |||
| assertThrows(OAuth2AccessDeniedException.class, () -> template.exchange(URL + "/write", GET, null, String.class)); | |||
| } | |||
| @Test | |||
| @@ -65,8 +62,7 @@ public class TestControllerTest extends AuthorizationTest { | |||
| ResponseEntity<String> response = template.exchange(URL + "/write", GET, null, String.class); | |||
| assertEquals(HttpStatus.OK, response.getStatusCode()); | |||
| assertEquals("WRITE", response.getBody()); | |||
| assertThrows(OAuth2AccessDeniedException.class, | |||
| () -> template.exchange(URL + "/read", GET, null, String.class)); | |||
| assertThrows(OAuth2AccessDeniedException.class, () -> template.exchange(URL + "/read", GET, null, String.class)); | |||
| } | |||
| @Test | |||
| @@ -22,7 +22,7 @@ public class BeetlConfig { | |||
| * Beetl需要显示的配置数据源,方可启动项目,大坑,切记! | |||
| */ | |||
| @Bean(name = "datasource") | |||
| public DataSource getDataSource(Environment env){ | |||
| public DataSource getDataSource(Environment env) { | |||
| HikariDataSource dataSource = new HikariDataSource(); | |||
| dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name")); | |||
| dataSource.setJdbcUrl(env.getProperty("spring.datasource.url")); | |||
| @@ -14,7 +14,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
| @SpringBootApplication | |||
| public class SpringBootDemoOrmJdbctemplateApplication { | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoOrmJdbctemplateApplication.class, args); | |||
| } | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoOrmJdbctemplateApplication.class, args); | |||
| } | |||
| } | |||
| @@ -16,10 +16,10 @@ import java.lang.annotation.Target; | |||
| @Retention(RetentionPolicy.RUNTIME) | |||
| @Target({ElementType.FIELD}) | |||
| public @interface Column { | |||
| /** | |||
| * 列名 | |||
| * | |||
| * @return 列名 | |||
| */ | |||
| String name(); | |||
| /** | |||
| * 列名 | |||
| * | |||
| * @return 列名 | |||
| */ | |||
| String name(); | |||
| } | |||
| @@ -16,10 +16,10 @@ import java.lang.annotation.Target; | |||
| @Retention(RetentionPolicy.RUNTIME) | |||
| @Target({ElementType.FIELD}) | |||
| public @interface Pk { | |||
| /** | |||
| * 自增 | |||
| * | |||
| * @return 自增主键 | |||
| */ | |||
| boolean auto() default true; | |||
| /** | |||
| * 自增 | |||
| * | |||
| * @return 自增主键 | |||
| */ | |||
| boolean auto() default true; | |||
| } | |||
| @@ -16,10 +16,10 @@ import java.lang.annotation.Target; | |||
| @Retention(RetentionPolicy.RUNTIME) | |||
| @Target({ElementType.TYPE}) | |||
| public @interface Table { | |||
| /** | |||
| * 表名 | |||
| * | |||
| * @return 表名 | |||
| */ | |||
| String name(); | |||
| /** | |||
| * 表名 | |||
| * | |||
| * @return 表名 | |||
| */ | |||
| String name(); | |||
| } | |||
| @@ -9,13 +9,13 @@ package com.xkcoding.orm.jdbctemplate.constant; | |||
| * @date Created in 2018-10-15 10:59 | |||
| */ | |||
| public interface Const { | |||
| /** | |||
| * 加密盐前缀 | |||
| */ | |||
| String SALT_PREFIX = "::SpringBootDemo::"; | |||
| /** | |||
| * 加密盐前缀 | |||
| */ | |||
| String SALT_PREFIX = "::SpringBootDemo::"; | |||
| /** | |||
| * 逗号分隔符 | |||
| */ | |||
| String SEPARATOR_COMMA = ","; | |||
| /** | |||
| * 逗号分隔符 | |||
| */ | |||
| String SEPARATOR_COMMA = ","; | |||
| } | |||
| @@ -20,40 +20,40 @@ import java.util.List; | |||
| @RestController | |||
| @Slf4j | |||
| public class UserController { | |||
| private final IUserService userService; | |||
| @Autowired | |||
| public UserController(IUserService userService) { | |||
| this.userService = userService; | |||
| } | |||
| @PostMapping("/user") | |||
| public Dict save(@RequestBody User user) { | |||
| Boolean save = userService.save(user); | |||
| return Dict.create().set("code", save ? 200 : 500).set("msg", save ? "成功" : "失败").set("data", save ? user : null); | |||
| } | |||
| @DeleteMapping("/user/{id}") | |||
| public Dict delete(@PathVariable Long id) { | |||
| Boolean delete = userService.delete(id); | |||
| return Dict.create().set("code", delete ? 200 : 500).set("msg", delete ? "成功" : "失败"); | |||
| } | |||
| @PutMapping("/user/{id}") | |||
| public Dict update(@RequestBody User user, @PathVariable Long id) { | |||
| Boolean update = userService.update(user, id); | |||
| return Dict.create().set("code", update ? 200 : 500).set("msg", update ? "成功" : "失败").set("data", update ? user : null); | |||
| } | |||
| @GetMapping("/user/{id}") | |||
| public Dict getUser(@PathVariable Long id) { | |||
| User user = userService.getUser(id); | |||
| return Dict.create().set("code", 200).set("msg", "成功").set("data", user); | |||
| } | |||
| @GetMapping("/user") | |||
| public Dict getUser(User user) { | |||
| List<User> userList = userService.getUser(user); | |||
| return Dict.create().set("code", 200).set("msg", "成功").set("data", userList); | |||
| } | |||
| private final IUserService userService; | |||
| @Autowired | |||
| public UserController(IUserService userService) { | |||
| this.userService = userService; | |||
| } | |||
| @PostMapping("/user") | |||
| public Dict save(@RequestBody User user) { | |||
| Boolean save = userService.save(user); | |||
| return Dict.create().set("code", save ? 200 : 500).set("msg", save ? "成功" : "失败").set("data", save ? user : null); | |||
| } | |||
| @DeleteMapping("/user/{id}") | |||
| public Dict delete(@PathVariable Long id) { | |||
| Boolean delete = userService.delete(id); | |||
| return Dict.create().set("code", delete ? 200 : 500).set("msg", delete ? "成功" : "失败"); | |||
| } | |||
| @PutMapping("/user/{id}") | |||
| public Dict update(@RequestBody User user, @PathVariable Long id) { | |||
| Boolean update = userService.update(user, id); | |||
| return Dict.create().set("code", update ? 200 : 500).set("msg", update ? "成功" : "失败").set("data", update ? user : null); | |||
| } | |||
| @GetMapping("/user/{id}") | |||
| public Dict getUser(@PathVariable Long id) { | |||
| User user = userService.getUser(id); | |||
| return Dict.create().set("code", 200).set("msg", "成功").set("data", user); | |||
| } | |||
| @GetMapping("/user") | |||
| public Dict getUser(User user) { | |||
| List<User> userList = userService.getUser(user); | |||
| return Dict.create().set("code", 200).set("msg", "成功").set("data", userList); | |||
| } | |||
| } | |||
| @@ -19,59 +19,59 @@ import java.util.List; | |||
| @Repository | |||
| public class UserDao extends BaseDao<User, Long> { | |||
| @Autowired | |||
| public UserDao(JdbcTemplate jdbcTemplate) { | |||
| super(jdbcTemplate); | |||
| } | |||
| @Autowired | |||
| public UserDao(JdbcTemplate jdbcTemplate) { | |||
| super(jdbcTemplate); | |||
| } | |||
| /** | |||
| * 保存用户 | |||
| * | |||
| * @param user 用户对象 | |||
| * @return 操作影响行数 | |||
| */ | |||
| public Integer insert(User user) { | |||
| return super.insert(user, true); | |||
| } | |||
| /** | |||
| * 保存用户 | |||
| * | |||
| * @param user 用户对象 | |||
| * @return 操作影响行数 | |||
| */ | |||
| public Integer insert(User user) { | |||
| return super.insert(user, true); | |||
| } | |||
| /** | |||
| * 根据主键删除用户 | |||
| * | |||
| * @param id 主键id | |||
| * @return 操作影响行数 | |||
| */ | |||
| public Integer delete(Long id) { | |||
| return super.deleteById(id); | |||
| } | |||
| /** | |||
| * 根据主键删除用户 | |||
| * | |||
| * @param id 主键id | |||
| * @return 操作影响行数 | |||
| */ | |||
| public Integer delete(Long id) { | |||
| return super.deleteById(id); | |||
| } | |||
| /** | |||
| * 更新用户 | |||
| * | |||
| * @param user 用户对象 | |||
| * @param id 主键id | |||
| * @return 操作影响行数 | |||
| */ | |||
| public Integer update(User user, Long id) { | |||
| return super.updateById(user, id, true); | |||
| } | |||
| /** | |||
| * 更新用户 | |||
| * | |||
| * @param user 用户对象 | |||
| * @param id 主键id | |||
| * @return 操作影响行数 | |||
| */ | |||
| public Integer update(User user, Long id) { | |||
| return super.updateById(user, id, true); | |||
| } | |||
| /** | |||
| * 根据主键获取用户 | |||
| * | |||
| * @param id 主键id | |||
| * @return id对应的用户 | |||
| */ | |||
| public User selectById(Long id) { | |||
| return super.findOneById(id); | |||
| } | |||
| /** | |||
| * 根据主键获取用户 | |||
| * | |||
| * @param id 主键id | |||
| * @return id对应的用户 | |||
| */ | |||
| public User selectById(Long id) { | |||
| return super.findOneById(id); | |||
| } | |||
| /** | |||
| * 根据查询条件获取用户列表 | |||
| * | |||
| * @param user 用户查询条件 | |||
| * @return 用户列表 | |||
| */ | |||
| public List<User> selectUserList(User user) { | |||
| return super.findByExample(user); | |||
| } | |||
| /** | |||
| * 根据查询条件获取用户列表 | |||
| * | |||
| * @param user 用户查询条件 | |||
| * @return 用户列表 | |||
| */ | |||
| public List<User> selectUserList(User user) { | |||
| return super.findByExample(user); | |||
| } | |||
| } | |||
| @@ -35,201 +35,201 @@ import java.util.stream.Stream; | |||
| */ | |||
| @Slf4j | |||
| public class BaseDao<T, P> { | |||
| private JdbcTemplate jdbcTemplate; | |||
| private Class<T> clazz; | |||
| @SuppressWarnings(value = "unchecked") | |||
| public BaseDao(JdbcTemplate jdbcTemplate) { | |||
| this.jdbcTemplate = jdbcTemplate; | |||
| clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; | |||
| } | |||
| /** | |||
| * 通用插入,自增列需要添加 {@link Pk} 注解 | |||
| * | |||
| * @param t 对象 | |||
| * @param ignoreNull 是否忽略 null 值 | |||
| * @return 操作的行数 | |||
| */ | |||
| protected Integer insert(T t, Boolean ignoreNull) { | |||
| String table = getTableName(t); | |||
| List<Field> filterField = getField(t, ignoreNull); | |||
| List<String> columnList = getColumns(filterField); | |||
| String columns = StrUtil.join(Const.SEPARATOR_COMMA, columnList); | |||
| // 构造占位符 | |||
| String params = StrUtil.repeatAndJoin("?", columnList.size(), Const.SEPARATOR_COMMA); | |||
| // 构造值 | |||
| Object[] values = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).toArray(); | |||
| String sql = StrUtil.format("INSERT INTO {table} ({columns}) VALUES ({params})", Dict.create().set("table", table).set("columns", columns).set("params", params)); | |||
| log.debug("【执行SQL】SQL:{}", sql); | |||
| log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(values)); | |||
| return jdbcTemplate.update(sql, values); | |||
| } | |||
| /** | |||
| * 通用根据主键删除 | |||
| * | |||
| * @param pk 主键 | |||
| * @return 影响行数 | |||
| */ | |||
| protected Integer deleteById(P pk) { | |||
| String tableName = getTableName(); | |||
| String sql = StrUtil.format("DELETE FROM {table} where id = ?", Dict.create().set("table", tableName)); | |||
| log.debug("【执行SQL】SQL:{}", sql); | |||
| log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(pk)); | |||
| return jdbcTemplate.update(sql, pk); | |||
| } | |||
| /** | |||
| * 通用根据主键更新,自增列需要添加 {@link Pk} 注解 | |||
| * | |||
| * @param t 对象 | |||
| * @param pk 主键 | |||
| * @param ignoreNull 是否忽略 null 值 | |||
| * @return 操作的行数 | |||
| */ | |||
| protected Integer updateById(T t, P pk, Boolean ignoreNull) { | |||
| String tableName = getTableName(t); | |||
| List<Field> filterField = getField(t, ignoreNull); | |||
| List<String> columnList = getColumns(filterField); | |||
| List<String> columns = columnList.stream().map(s -> StrUtil.appendIfMissing(s, " = ?")).collect(Collectors.toList()); | |||
| String params = StrUtil.join(Const.SEPARATOR_COMMA, columns); | |||
| // 构造值 | |||
| List<Object> valueList = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).collect(Collectors.toList()); | |||
| valueList.add(pk); | |||
| Object[] values = ArrayUtil.toArray(valueList, Object.class); | |||
| String sql = StrUtil.format("UPDATE {table} SET {params} where id = ?", Dict.create().set("table", tableName).set("params", params)); | |||
| log.debug("【执行SQL】SQL:{}", sql); | |||
| log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(values)); | |||
| return jdbcTemplate.update(sql, values); | |||
| } | |||
| /** | |||
| * 通用根据主键查询单条记录 | |||
| * | |||
| * @param pk 主键 | |||
| * @return 单条记录 | |||
| */ | |||
| public T findOneById(P pk) { | |||
| String tableName = getTableName(); | |||
| String sql = StrUtil.format("SELECT * FROM {table} where id = ?", Dict.create().set("table", tableName)); | |||
| RowMapper<T> rowMapper = new BeanPropertyRowMapper<>(clazz); | |||
| log.debug("【执行SQL】SQL:{}", sql); | |||
| log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(pk)); | |||
| return jdbcTemplate.queryForObject(sql, new Object[]{pk}, rowMapper); | |||
| } | |||
| /** | |||
| * 根据对象查询 | |||
| * | |||
| * @param t 查询条件 | |||
| * @return 对象列表 | |||
| */ | |||
| public List<T> findByExample(T t) { | |||
| String tableName = getTableName(t); | |||
| List<Field> filterField = getField(t, true); | |||
| List<String> columnList = getColumns(filterField); | |||
| List<String> columns = columnList.stream().map(s -> " and " + s + " = ? ").collect(Collectors.toList()); | |||
| String where = StrUtil.join(" ", columns); | |||
| // 构造值 | |||
| Object[] values = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).toArray(); | |||
| String sql = StrUtil.format("SELECT * FROM {table} where 1=1 {where}", Dict.create().set("table", tableName).set("where", StrUtil.isBlank(where) ? "" : where)); | |||
| log.debug("【执行SQL】SQL:{}", sql); | |||
| log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(values)); | |||
| List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql, values); | |||
| List<T> ret = CollUtil.newArrayList(); | |||
| maps.forEach(map -> ret.add(BeanUtil.fillBeanWithMap(map, ReflectUtil.newInstance(clazz), true, false))); | |||
| return ret; | |||
| } | |||
| /** | |||
| * 获取表名 | |||
| * | |||
| * @param t 对象 | |||
| * @return 表名 | |||
| */ | |||
| private String getTableName(T t) { | |||
| Table tableAnnotation = t.getClass().getAnnotation(Table.class); | |||
| if (ObjectUtil.isNotNull(tableAnnotation)) { | |||
| return StrUtil.format("`{}`", tableAnnotation.name()); | |||
| } else { | |||
| return StrUtil.format("`{}`", t.getClass().getName().toLowerCase()); | |||
| } | |||
| } | |||
| /** | |||
| * 获取表名 | |||
| * | |||
| * @return 表名 | |||
| */ | |||
| private String getTableName() { | |||
| Table tableAnnotation = clazz.getAnnotation(Table.class); | |||
| if (ObjectUtil.isNotNull(tableAnnotation)) { | |||
| return StrUtil.format("`{}`", tableAnnotation.name()); | |||
| } else { | |||
| return StrUtil.format("`{}`", clazz.getName().toLowerCase()); | |||
| } | |||
| } | |||
| /** | |||
| * 获取列 | |||
| * | |||
| * @param fieldList 字段列表 | |||
| * @return 列信息列表 | |||
| */ | |||
| private List<String> getColumns(List<Field> fieldList) { | |||
| // 构造列 | |||
| List<String> columnList = CollUtil.newArrayList(); | |||
| for (Field field : fieldList) { | |||
| Column columnAnnotation = field.getAnnotation(Column.class); | |||
| String columnName; | |||
| if (ObjectUtil.isNotNull(columnAnnotation)) { | |||
| columnName = columnAnnotation.name(); | |||
| } else { | |||
| columnName = field.getName(); | |||
| } | |||
| columnList.add(StrUtil.format("`{}`", columnName)); | |||
| } | |||
| return columnList; | |||
| } | |||
| /** | |||
| * 获取字段列表 {@code 过滤数据库中不存在的字段,以及自增列} | |||
| * | |||
| * @param t 对象 | |||
| * @param ignoreNull 是否忽略空值 | |||
| * @return 字段列表 | |||
| */ | |||
| private List<Field> getField(T t, Boolean ignoreNull) { | |||
| // 获取所有字段,包含父类中的字段 | |||
| Field[] fields = ReflectUtil.getFields(t.getClass()); | |||
| // 过滤数据库中不存在的字段,以及自增列 | |||
| List<Field> filterField; | |||
| Stream<Field> fieldStream = CollUtil.toList(fields).stream().filter(field -> ObjectUtil.isNull(field.getAnnotation(Ignore.class)) || ObjectUtil.isNull(field.getAnnotation(Pk.class))); | |||
| // 是否过滤字段值为null的字段 | |||
| if (ignoreNull) { | |||
| filterField = fieldStream.filter(field -> ObjectUtil.isNotNull(ReflectUtil.getFieldValue(t, field))).collect(Collectors.toList()); | |||
| } else { | |||
| filterField = fieldStream.collect(Collectors.toList()); | |||
| } | |||
| return filterField; | |||
| } | |||
| private JdbcTemplate jdbcTemplate; | |||
| private Class<T> clazz; | |||
| @SuppressWarnings(value = "unchecked") | |||
| public BaseDao(JdbcTemplate jdbcTemplate) { | |||
| this.jdbcTemplate = jdbcTemplate; | |||
| clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; | |||
| } | |||
| /** | |||
| * 通用插入,自增列需要添加 {@link Pk} 注解 | |||
| * | |||
| * @param t 对象 | |||
| * @param ignoreNull 是否忽略 null 值 | |||
| * @return 操作的行数 | |||
| */ | |||
| protected Integer insert(T t, Boolean ignoreNull) { | |||
| String table = getTableName(t); | |||
| List<Field> filterField = getField(t, ignoreNull); | |||
| List<String> columnList = getColumns(filterField); | |||
| String columns = StrUtil.join(Const.SEPARATOR_COMMA, columnList); | |||
| // 构造占位符 | |||
| String params = StrUtil.repeatAndJoin("?", columnList.size(), Const.SEPARATOR_COMMA); | |||
| // 构造值 | |||
| Object[] values = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).toArray(); | |||
| String sql = StrUtil.format("INSERT INTO {table} ({columns}) VALUES ({params})", Dict.create().set("table", table).set("columns", columns).set("params", params)); | |||
| log.debug("【执行SQL】SQL:{}", sql); | |||
| log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(values)); | |||
| return jdbcTemplate.update(sql, values); | |||
| } | |||
| /** | |||
| * 通用根据主键删除 | |||
| * | |||
| * @param pk 主键 | |||
| * @return 影响行数 | |||
| */ | |||
| protected Integer deleteById(P pk) { | |||
| String tableName = getTableName(); | |||
| String sql = StrUtil.format("DELETE FROM {table} where id = ?", Dict.create().set("table", tableName)); | |||
| log.debug("【执行SQL】SQL:{}", sql); | |||
| log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(pk)); | |||
| return jdbcTemplate.update(sql, pk); | |||
| } | |||
| /** | |||
| * 通用根据主键更新,自增列需要添加 {@link Pk} 注解 | |||
| * | |||
| * @param t 对象 | |||
| * @param pk 主键 | |||
| * @param ignoreNull 是否忽略 null 值 | |||
| * @return 操作的行数 | |||
| */ | |||
| protected Integer updateById(T t, P pk, Boolean ignoreNull) { | |||
| String tableName = getTableName(t); | |||
| List<Field> filterField = getField(t, ignoreNull); | |||
| List<String> columnList = getColumns(filterField); | |||
| List<String> columns = columnList.stream().map(s -> StrUtil.appendIfMissing(s, " = ?")).collect(Collectors.toList()); | |||
| String params = StrUtil.join(Const.SEPARATOR_COMMA, columns); | |||
| // 构造值 | |||
| List<Object> valueList = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).collect(Collectors.toList()); | |||
| valueList.add(pk); | |||
| Object[] values = ArrayUtil.toArray(valueList, Object.class); | |||
| String sql = StrUtil.format("UPDATE {table} SET {params} where id = ?", Dict.create().set("table", tableName).set("params", params)); | |||
| log.debug("【执行SQL】SQL:{}", sql); | |||
| log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(values)); | |||
| return jdbcTemplate.update(sql, values); | |||
| } | |||
| /** | |||
| * 通用根据主键查询单条记录 | |||
| * | |||
| * @param pk 主键 | |||
| * @return 单条记录 | |||
| */ | |||
| public T findOneById(P pk) { | |||
| String tableName = getTableName(); | |||
| String sql = StrUtil.format("SELECT * FROM {table} where id = ?", Dict.create().set("table", tableName)); | |||
| RowMapper<T> rowMapper = new BeanPropertyRowMapper<>(clazz); | |||
| log.debug("【执行SQL】SQL:{}", sql); | |||
| log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(pk)); | |||
| return jdbcTemplate.queryForObject(sql, new Object[]{pk}, rowMapper); | |||
| } | |||
| /** | |||
| * 根据对象查询 | |||
| * | |||
| * @param t 查询条件 | |||
| * @return 对象列表 | |||
| */ | |||
| public List<T> findByExample(T t) { | |||
| String tableName = getTableName(t); | |||
| List<Field> filterField = getField(t, true); | |||
| List<String> columnList = getColumns(filterField); | |||
| List<String> columns = columnList.stream().map(s -> " and " + s + " = ? ").collect(Collectors.toList()); | |||
| String where = StrUtil.join(" ", columns); | |||
| // 构造值 | |||
| Object[] values = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).toArray(); | |||
| String sql = StrUtil.format("SELECT * FROM {table} where 1=1 {where}", Dict.create().set("table", tableName).set("where", StrUtil.isBlank(where) ? "" : where)); | |||
| log.debug("【执行SQL】SQL:{}", sql); | |||
| log.debug("【执行SQL】参数:{}", JSONUtil.toJsonStr(values)); | |||
| List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql, values); | |||
| List<T> ret = CollUtil.newArrayList(); | |||
| maps.forEach(map -> ret.add(BeanUtil.fillBeanWithMap(map, ReflectUtil.newInstance(clazz), true, false))); | |||
| return ret; | |||
| } | |||
| /** | |||
| * 获取表名 | |||
| * | |||
| * @param t 对象 | |||
| * @return 表名 | |||
| */ | |||
| private String getTableName(T t) { | |||
| Table tableAnnotation = t.getClass().getAnnotation(Table.class); | |||
| if (ObjectUtil.isNotNull(tableAnnotation)) { | |||
| return StrUtil.format("`{}`", tableAnnotation.name()); | |||
| } else { | |||
| return StrUtil.format("`{}`", t.getClass().getName().toLowerCase()); | |||
| } | |||
| } | |||
| /** | |||
| * 获取表名 | |||
| * | |||
| * @return 表名 | |||
| */ | |||
| private String getTableName() { | |||
| Table tableAnnotation = clazz.getAnnotation(Table.class); | |||
| if (ObjectUtil.isNotNull(tableAnnotation)) { | |||
| return StrUtil.format("`{}`", tableAnnotation.name()); | |||
| } else { | |||
| return StrUtil.format("`{}`", clazz.getName().toLowerCase()); | |||
| } | |||
| } | |||
| /** | |||
| * 获取列 | |||
| * | |||
| * @param fieldList 字段列表 | |||
| * @return 列信息列表 | |||
| */ | |||
| private List<String> getColumns(List<Field> fieldList) { | |||
| // 构造列 | |||
| List<String> columnList = CollUtil.newArrayList(); | |||
| for (Field field : fieldList) { | |||
| Column columnAnnotation = field.getAnnotation(Column.class); | |||
| String columnName; | |||
| if (ObjectUtil.isNotNull(columnAnnotation)) { | |||
| columnName = columnAnnotation.name(); | |||
| } else { | |||
| columnName = field.getName(); | |||
| } | |||
| columnList.add(StrUtil.format("`{}`", columnName)); | |||
| } | |||
| return columnList; | |||
| } | |||
| /** | |||
| * 获取字段列表 {@code 过滤数据库中不存在的字段,以及自增列} | |||
| * | |||
| * @param t 对象 | |||
| * @param ignoreNull 是否忽略空值 | |||
| * @return 字段列表 | |||
| */ | |||
| private List<Field> getField(T t, Boolean ignoreNull) { | |||
| // 获取所有字段,包含父类中的字段 | |||
| Field[] fields = ReflectUtil.getFields(t.getClass()); | |||
| // 过滤数据库中不存在的字段,以及自增列 | |||
| List<Field> filterField; | |||
| Stream<Field> fieldStream = CollUtil.toList(fields).stream().filter(field -> ObjectUtil.isNull(field.getAnnotation(Ignore.class)) || ObjectUtil.isNull(field.getAnnotation(Pk.class))); | |||
| // 是否过滤字段值为null的字段 | |||
| if (ignoreNull) { | |||
| filterField = fieldStream.filter(field -> ObjectUtil.isNotNull(ReflectUtil.getFieldValue(t, field))).collect(Collectors.toList()); | |||
| } else { | |||
| filterField = fieldStream.collect(Collectors.toList()); | |||
| } | |||
| return filterField; | |||
| } | |||
| } | |||
| @@ -1,7 +1,7 @@ | |||
| package com.xkcoding.orm.jdbctemplate.entity; | |||
| import com.xkcoding.orm.jdbctemplate.annotation.Pk; | |||
| import com.xkcoding.orm.jdbctemplate.annotation.Column; | |||
| import com.xkcoding.orm.jdbctemplate.annotation.Pk; | |||
| import com.xkcoding.orm.jdbctemplate.annotation.Table; | |||
| import lombok.Data; | |||
| @@ -19,58 +19,58 @@ import java.util.Date; | |||
| @Data | |||
| @Table(name = "orm_user") | |||
| public class User implements Serializable { | |||
| /** | |||
| * 主键 | |||
| */ | |||
| @Pk | |||
| private Long id; | |||
| /** | |||
| * 主键 | |||
| */ | |||
| @Pk | |||
| private Long id; | |||
| /** | |||
| * 用户名 | |||
| */ | |||
| private String name; | |||
| /** | |||
| * 用户名 | |||
| */ | |||
| private String name; | |||
| /** | |||
| * 加密后的密码 | |||
| */ | |||
| private String password; | |||
| /** | |||
| * 加密后的密码 | |||
| */ | |||
| private String password; | |||
| /** | |||
| * 加密使用的盐 | |||
| */ | |||
| private String salt; | |||
| /** | |||
| * 加密使用的盐 | |||
| */ | |||
| private String salt; | |||
| /** | |||
| * 邮箱 | |||
| */ | |||
| private String email; | |||
| /** | |||
| * 邮箱 | |||
| */ | |||
| private String email; | |||
| /** | |||
| * 手机号码 | |||
| */ | |||
| @Column(name = "phone_number") | |||
| private String phoneNumber; | |||
| /** | |||
| * 手机号码 | |||
| */ | |||
| @Column(name = "phone_number") | |||
| private String phoneNumber; | |||
| /** | |||
| * 状态,-1:逻辑删除,0:禁用,1:启用 | |||
| */ | |||
| private Integer status; | |||
| /** | |||
| * 状态,-1:逻辑删除,0:禁用,1:启用 | |||
| */ | |||
| private Integer status; | |||
| /** | |||
| * 创建时间 | |||
| */ | |||
| @Column(name = "create_time") | |||
| private Date createTime; | |||
| /** | |||
| * 创建时间 | |||
| */ | |||
| @Column(name = "create_time") | |||
| private Date createTime; | |||
| /** | |||
| * 上次登录时间 | |||
| */ | |||
| @Column(name = "last_login_time") | |||
| private Date lastLoginTime; | |||
| /** | |||
| * 上次登录时间 | |||
| */ | |||
| @Column(name = "last_login_time") | |||
| private Date lastLoginTime; | |||
| /** | |||
| * 上次更新时间 | |||
| */ | |||
| @Column(name = "last_update_time") | |||
| private Date lastUpdateTime; | |||
| /** | |||
| * 上次更新时间 | |||
| */ | |||
| @Column(name = "last_update_time") | |||
| private Date lastUpdateTime; | |||
| } | |||
| @@ -13,45 +13,45 @@ import java.util.List; | |||
| * @date Created in 2018-10-15 13:51 | |||
| */ | |||
| public interface IUserService { | |||
| /** | |||
| * 保存用户 | |||
| * | |||
| * @param user 用户实体 | |||
| * @return 保存成功 {@code true} 保存失败 {@code false} | |||
| */ | |||
| Boolean save(User user); | |||
| /** | |||
| * 删除用户 | |||
| * | |||
| * @param id 主键id | |||
| * @return 删除成功 {@code true} 删除失败 {@code false} | |||
| */ | |||
| Boolean delete(Long id); | |||
| /** | |||
| * 更新用户 | |||
| * | |||
| * @param user 用户实体 | |||
| * @param id 主键id | |||
| * @return 更新成功 {@code true} 更新失败 {@code false} | |||
| */ | |||
| Boolean update(User user, Long id); | |||
| /** | |||
| * 获取单个用户 | |||
| * | |||
| * @param id 主键id | |||
| * @return 单个用户对象 | |||
| */ | |||
| User getUser(Long id); | |||
| /** | |||
| * 获取用户列表 | |||
| * | |||
| * @param user 用户实体 | |||
| * @return 用户列表 | |||
| */ | |||
| List<User> getUser(User user); | |||
| /** | |||
| * 保存用户 | |||
| * | |||
| * @param user 用户实体 | |||
| * @return 保存成功 {@code true} 保存失败 {@code false} | |||
| */ | |||
| Boolean save(User user); | |||
| /** | |||
| * 删除用户 | |||
| * | |||
| * @param id 主键id | |||
| * @return 删除成功 {@code true} 删除失败 {@code false} | |||
| */ | |||
| Boolean delete(Long id); | |||
| /** | |||
| * 更新用户 | |||
| * | |||
| * @param user 用户实体 | |||
| * @param id 主键id | |||
| * @return 更新成功 {@code true} 更新失败 {@code false} | |||
| */ | |||
| Boolean update(User user, Long id); | |||
| /** | |||
| * 获取单个用户 | |||
| * | |||
| * @param id 主键id | |||
| * @return 单个用户对象 | |||
| */ | |||
| User getUser(Long id); | |||
| /** | |||
| * 获取用户列表 | |||
| * | |||
| * @param user 用户实体 | |||
| * @return 用户列表 | |||
| */ | |||
| List<User> getUser(User user); | |||
| } | |||
| @@ -25,81 +25,81 @@ import java.util.List; | |||
| */ | |||
| @Service | |||
| public class UserServiceImpl implements IUserService { | |||
| private final UserDao userDao; | |||
| private final UserDao userDao; | |||
| @Autowired | |||
| public UserServiceImpl(UserDao userDao) { | |||
| this.userDao = userDao; | |||
| } | |||
| @Autowired | |||
| public UserServiceImpl(UserDao userDao) { | |||
| this.userDao = userDao; | |||
| } | |||
| /** | |||
| * 保存用户 | |||
| * | |||
| * @param user 用户实体 | |||
| * @return 保存成功 {@code true} 保存失败 {@code false} | |||
| */ | |||
| @Override | |||
| public Boolean save(User user) { | |||
| String rawPass = user.getPassword(); | |||
| String salt = IdUtil.simpleUUID(); | |||
| String pass = SecureUtil.md5(rawPass + Const.SALT_PREFIX + salt); | |||
| user.setPassword(pass); | |||
| user.setSalt(salt); | |||
| return userDao.insert(user) > 0; | |||
| } | |||
| /** | |||
| * 保存用户 | |||
| * | |||
| * @param user 用户实体 | |||
| * @return 保存成功 {@code true} 保存失败 {@code false} | |||
| */ | |||
| @Override | |||
| public Boolean save(User user) { | |||
| String rawPass = user.getPassword(); | |||
| String salt = IdUtil.simpleUUID(); | |||
| String pass = SecureUtil.md5(rawPass + Const.SALT_PREFIX + salt); | |||
| user.setPassword(pass); | |||
| user.setSalt(salt); | |||
| return userDao.insert(user) > 0; | |||
| } | |||
| /** | |||
| * 删除用户 | |||
| * | |||
| * @param id 主键id | |||
| * @return 删除成功 {@code true} 删除失败 {@code false} | |||
| */ | |||
| @Override | |||
| public Boolean delete(Long id) { | |||
| return userDao.delete(id) > 0; | |||
| } | |||
| /** | |||
| * 删除用户 | |||
| * | |||
| * @param id 主键id | |||
| * @return 删除成功 {@code true} 删除失败 {@code false} | |||
| */ | |||
| @Override | |||
| public Boolean delete(Long id) { | |||
| return userDao.delete(id) > 0; | |||
| } | |||
| /** | |||
| * 更新用户 | |||
| * | |||
| * @param user 用户实体 | |||
| * @param id 主键id | |||
| * @return 更新成功 {@code true} 更新失败 {@code false} | |||
| */ | |||
| @Override | |||
| public Boolean update(User user, Long id) { | |||
| User exist = getUser(id); | |||
| if (StrUtil.isNotBlank(user.getPassword())) { | |||
| String rawPass = user.getPassword(); | |||
| String salt = IdUtil.simpleUUID(); | |||
| String pass = SecureUtil.md5(rawPass + Const.SALT_PREFIX + salt); | |||
| user.setPassword(pass); | |||
| user.setSalt(salt); | |||
| } | |||
| BeanUtil.copyProperties(user, exist, CopyOptions.create().setIgnoreNullValue(true)); | |||
| exist.setLastUpdateTime(new DateTime()); | |||
| return userDao.update(exist, id) > 0; | |||
| } | |||
| /** | |||
| * 更新用户 | |||
| * | |||
| * @param user 用户实体 | |||
| * @param id 主键id | |||
| * @return 更新成功 {@code true} 更新失败 {@code false} | |||
| */ | |||
| @Override | |||
| public Boolean update(User user, Long id) { | |||
| User exist = getUser(id); | |||
| if (StrUtil.isNotBlank(user.getPassword())) { | |||
| String rawPass = user.getPassword(); | |||
| String salt = IdUtil.simpleUUID(); | |||
| String pass = SecureUtil.md5(rawPass + Const.SALT_PREFIX + salt); | |||
| user.setPassword(pass); | |||
| user.setSalt(salt); | |||
| } | |||
| BeanUtil.copyProperties(user, exist, CopyOptions.create().setIgnoreNullValue(true)); | |||
| exist.setLastUpdateTime(new DateTime()); | |||
| return userDao.update(exist, id) > 0; | |||
| } | |||
| /** | |||
| * 获取单个用户 | |||
| * | |||
| * @param id 主键id | |||
| * @return 单个用户对象 | |||
| */ | |||
| @Override | |||
| public User getUser(Long id) { | |||
| return userDao.findOneById(id); | |||
| } | |||
| /** | |||
| * 获取单个用户 | |||
| * | |||
| * @param id 主键id | |||
| * @return 单个用户对象 | |||
| */ | |||
| @Override | |||
| public User getUser(Long id) { | |||
| return userDao.findOneById(id); | |||
| } | |||
| /** | |||
| * 获取用户列表 | |||
| * | |||
| * @param user 用户实体 | |||
| * @return 用户列表 | |||
| */ | |||
| @Override | |||
| public List<User> getUser(User user) { | |||
| return userDao.findByExample(user); | |||
| } | |||
| /** | |||
| * 获取用户列表 | |||
| * | |||
| * @param user 用户实体 | |||
| * @return 用户列表 | |||
| */ | |||
| @Override | |||
| public List<User> getUser(User user) { | |||
| return userDao.findByExample(user); | |||
| } | |||
| } | |||
| @@ -14,7 +14,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
| @SpringBootApplication | |||
| public class SpringBootDemoOrmJpaApplication { | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoOrmJpaApplication.class, args); | |||
| } | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoOrmJpaApplication.class, args); | |||
| } | |||
| } | |||
| @@ -93,7 +93,7 @@ public class UserMapperTest extends SpringBootDemoOrmMybatisMapperPageApplicatio | |||
| * 测试通用Mapper - 查询单个 | |||
| */ | |||
| @Test | |||
| public void testQueryOne(){ | |||
| public void testQueryOne() { | |||
| User user = userMapper.selectByPrimaryKey(1L); | |||
| Assert.assertNotNull(user); | |||
| log.debug("【user】= {}", user); | |||
| @@ -23,7 +23,7 @@ public class MybatisPlusConfig { | |||
| * 性能分析拦截器,不建议生产使用 | |||
| */ | |||
| @Bean | |||
| public PerformanceInterceptor performanceInterceptor(){ | |||
| public PerformanceInterceptor performanceInterceptor() { | |||
| return new PerformanceInterceptor(); | |||
| } | |||
| @@ -9,8 +9,8 @@ import org.springframework.test.context.junit4.SpringRunner; | |||
| @SpringBootTest | |||
| public class SpringBootDemoOrmMybatisPlusApplicationTests { | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| } | |||
| @@ -14,7 +14,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
| @SpringBootApplication | |||
| public class SpringBootDemoPropertiesApplication { | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoPropertiesApplication.class, args); | |||
| } | |||
| public static void main(String[] args) { | |||
| SpringApplication.run(SpringBootDemoPropertiesApplication.class, args); | |||
| } | |||
| } | |||
| @@ -17,17 +17,17 @@ import org.springframework.web.bind.annotation.RestController; | |||
| */ | |||
| @RestController | |||
| public class PropertyController { | |||
| private final ApplicationProperty applicationProperty; | |||
| private final DeveloperProperty developerProperty; | |||
| private final ApplicationProperty applicationProperty; | |||
| private final DeveloperProperty developerProperty; | |||
| @Autowired | |||
| public PropertyController(ApplicationProperty applicationProperty, DeveloperProperty developerProperty) { | |||
| this.applicationProperty = applicationProperty; | |||
| this.developerProperty = developerProperty; | |||
| } | |||
| @Autowired | |||
| public PropertyController(ApplicationProperty applicationProperty, DeveloperProperty developerProperty) { | |||
| this.applicationProperty = applicationProperty; | |||
| this.developerProperty = developerProperty; | |||
| } | |||
| @GetMapping("/property") | |||
| public Dict index() { | |||
| return Dict.create().set("applicationProperty", applicationProperty).set("developerProperty", developerProperty); | |||
| } | |||
| @GetMapping("/property") | |||
| public Dict index() { | |||
| return Dict.create().set("applicationProperty", applicationProperty).set("developerProperty", developerProperty); | |||
| } | |||
| } | |||
| @@ -15,8 +15,8 @@ import org.springframework.stereotype.Component; | |||
| @Data | |||
| @Component | |||
| public class ApplicationProperty { | |||
| @Value("${application.name}") | |||
| private String name; | |||
| @Value("${application.version}") | |||
| private String version; | |||
| @Value("${application.name}") | |||
| private String name; | |||
| @Value("${application.version}") | |||
| private String version; | |||
| } | |||
| @@ -16,8 +16,8 @@ import org.springframework.stereotype.Component; | |||
| @ConfigurationProperties(prefix = "developer") | |||
| @Component | |||
| public class DeveloperProperty { | |||
| private String name; | |||
| private String website; | |||
| private String qq; | |||
| private String phoneNumber; | |||
| private String name; | |||
| private String website; | |||
| private String qq; | |||
| private String phoneNumber; | |||
| } | |||
| @@ -9,8 +9,8 @@ import org.springframework.test.context.junit4.SpringRunner; | |||
| @SpringBootTest | |||
| public class SpringBootDemoPropertiesApplicationTests { | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| @Test | |||
| public void contextLoads() { | |||
| } | |||
| } | |||
| @@ -54,7 +54,7 @@ public class RateLimiterAspect { | |||
| String key = rateLimiter.key(); | |||
| // 默认用类名+方法名做限流的 key 前缀 | |||
| if (StrUtil.isBlank(key)) { | |||
| key = method.getDeclaringClass().getName()+StrUtil.DOT+method.getName(); | |||
| key = method.getDeclaringClass().getName() + StrUtil.DOT + method.getName(); | |||
| } | |||
| // 最终限流的 key 为 前缀 + IP地址 | |||
| // TODO: 此时需要考虑局域网多用户访问的情况,因此 key 后续需要加上方法参数更加合理 | |||
| @@ -14,29 +14,29 @@ import lombok.EqualsAndHashCode; | |||
| @EqualsAndHashCode(callSuper = true) | |||
| @Data | |||
| public class BaseException extends RuntimeException { | |||
| private Integer code; | |||
| private String message; | |||
| private Object data; | |||
| private Integer code; | |||
| private String message; | |||
| private Object data; | |||
| public BaseException(Status status) { | |||
| super(status.getMessage()); | |||
| this.code = status.getCode(); | |||
| this.message = status.getMessage(); | |||
| } | |||
| public BaseException(Status status) { | |||
| super(status.getMessage()); | |||
| this.code = status.getCode(); | |||
| this.message = status.getMessage(); | |||
| } | |||
| public BaseException(Status status, Object data) { | |||
| this(status); | |||
| this.data = data; | |||
| } | |||
| public BaseException(Status status, Object data) { | |||
| this(status); | |||
| this.data = data; | |||
| } | |||
| public BaseException(Integer code, String message) { | |||
| super(message); | |||
| this.code = code; | |||
| this.message = message; | |||
| } | |||
| public BaseException(Integer code, String message) { | |||
| super(message); | |||
| this.code = code; | |||
| this.message = message; | |||
| } | |||
| public BaseException(Integer code, String message, Object data) { | |||
| this(code, message); | |||
| this.data = data; | |||
| } | |||
| public BaseException(Integer code, String message, Object data) { | |||
| this(code, message); | |||
| this.data = data; | |||
| } | |||
| } | |||
| @@ -110,8 +110,7 @@ public enum Status implements IStatus { | |||
| public static Status fromCode(Integer code) { | |||
| Status[] statuses = Status.values(); | |||
| for (Status status : statuses) { | |||
| if (status.getCode() | |||
| .equals(code)) { | |||
| if (status.getCode().equals(code)) { | |||
| return status; | |||
| } | |||
| } | |||
| @@ -65,8 +65,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { | |||
| UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); | |||
| authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); | |||
| SecurityContextHolder.getContext() | |||
| .setAuthentication(authentication); | |||
| SecurityContextHolder.getContext().setAuthentication(authentication); | |||
| filterChain.doFilter(request, response); | |||
| } catch (SecurityException e) { | |||
| ResponseUtil.renderJson(response, e); | |||
| @@ -95,43 +94,34 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { | |||
| switch (httpMethod) { | |||
| case GET: | |||
| ignores.addAll(customConfig.getIgnores() | |||
| .getGet()); | |||
| ignores.addAll(customConfig.getIgnores().getGet()); | |||
| break; | |||
| case PUT: | |||
| ignores.addAll(customConfig.getIgnores() | |||
| .getPut()); | |||
| ignores.addAll(customConfig.getIgnores().getPut()); | |||
| break; | |||
| case HEAD: | |||
| ignores.addAll(customConfig.getIgnores() | |||
| .getHead()); | |||
| ignores.addAll(customConfig.getIgnores().getHead()); | |||
| break; | |||
| case POST: | |||
| ignores.addAll(customConfig.getIgnores() | |||
| .getPost()); | |||
| ignores.addAll(customConfig.getIgnores().getPost()); | |||
| break; | |||
| case PATCH: | |||
| ignores.addAll(customConfig.getIgnores() | |||
| .getPatch()); | |||
| ignores.addAll(customConfig.getIgnores().getPatch()); | |||
| break; | |||
| case TRACE: | |||
| ignores.addAll(customConfig.getIgnores() | |||
| .getTrace()); | |||
| ignores.addAll(customConfig.getIgnores().getTrace()); | |||
| break; | |||
| case DELETE: | |||
| ignores.addAll(customConfig.getIgnores() | |||
| .getDelete()); | |||
| ignores.addAll(customConfig.getIgnores().getDelete()); | |||
| break; | |||
| case OPTIONS: | |||
| ignores.addAll(customConfig.getIgnores() | |||
| .getOptions()); | |||
| ignores.addAll(customConfig.getIgnores().getOptions()); | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| ignores.addAll(customConfig.getIgnores() | |||
| .getPattern()); | |||
| ignores.addAll(customConfig.getIgnores().getPattern()); | |||
| if (CollUtil.isNotEmpty(ignores)) { | |||
| for (String ignore : ignores) { | |||
| @@ -58,20 +58,17 @@ public class RbacAuthorityService { | |||
| Long userId = principal.getId(); | |||
| List<Role> roles = roleDao.selectByUserId(userId); | |||
| List<Long> roleIds = roles.stream() | |||
| .map(Role::getId) | |||
| .collect(Collectors.toList()); | |||
| List<Long> roleIds = roles.stream().map(Role::getId).collect(Collectors.toList()); | |||
| List<Permission> permissions = permissionDao.selectByRoleIdList(roleIds); | |||
| //获取资源,前后端分离,所以过滤页面权限,只保留按钮权限 | |||
| List<Permission> btnPerms = permissions.stream() | |||
| // 过滤页面权限 | |||
| .filter(permission -> Objects.equals(permission.getType(), Consts.BUTTON)) | |||
| // 过滤 URL 为空 | |||
| .filter(permission -> StrUtil.isNotBlank(permission.getUrl())) | |||
| // 过滤 METHOD 为空 | |||
| .filter(permission -> StrUtil.isNotBlank(permission.getMethod())) | |||
| .collect(Collectors.toList()); | |||
| // 过滤页面权限 | |||
| .filter(permission -> Objects.equals(permission.getType(), Consts.BUTTON)) | |||
| // 过滤 URL 为空 | |||
| .filter(permission -> StrUtil.isNotBlank(permission.getUrl())) | |||
| // 过滤 METHOD 为空 | |||
| .filter(permission -> StrUtil.isNotBlank(permission.getMethod())).collect(Collectors.toList()); | |||
| for (Permission btnPerm : btnPerms) { | |||
| AntPathRequestMatcher antPathMatcher = new AntPathRequestMatcher(btnPerm.getUrl(), btnPerm.getMethod()); | |||
| @@ -104,8 +101,7 @@ public class RbacAuthorityService { | |||
| // 2:new AntPathRequestMatcher(uri) 这种方式不校验请求方法,只校验请求路径 | |||
| AntPathRequestMatcher antPathMatcher = new AntPathRequestMatcher(uri); | |||
| if (antPathMatcher.matches(request)) { | |||
| if (!urlMapping.get(uri) | |||
| .contains(currentMethod)) { | |||
| if (!urlMapping.get(uri).contains(currentMethod)) { | |||
| throw new SecurityException(Status.HTTP_BAD_METHOD); | |||
| } else { | |||
| return; | |||
| @@ -129,15 +125,11 @@ public class RbacAuthorityService { | |||
| handlerMethods.forEach((k, v) -> { | |||
| // 获取当前 key 下的获取所有URL | |||
| Set<String> url = k.getPatternsCondition() | |||
| .getPatterns(); | |||
| Set<String> url = k.getPatternsCondition().getPatterns(); | |||
| RequestMethodsRequestCondition method = k.getMethodsCondition(); | |||
| // 为每个URL添加所有的请求方法 | |||
| url.forEach(s -> urlMapping.putAll(s, method.getMethods() | |||
| .stream() | |||
| .map(Enum::toString) | |||
| .collect(Collectors.toList()))); | |||
| url.forEach(s -> urlMapping.putAll(s, method.getMethods().stream().map(Enum::toString).collect(Collectors.toList()))); | |||
| }); | |||
| return urlMapping; | |||
| @@ -19,9 +19,6 @@ public class WebMvcConfig implements WebMvcConfigurer { | |||
| @Override | |||
| public void addCorsMappings(CorsRegistry registry) { | |||
| registry.addMapping("/**") | |||
| .allowedOrigins("*") | |||
| .allowedMethods("HEAD", "OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE") | |||
| .maxAge(MAX_AGE_SECS); | |||
| registry.addMapping("/**").allowedOrigins("*").allowedMethods("HEAD", "OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE").maxAge(MAX_AGE_SECS); | |||
| } | |||
| } | |||
| @@ -46,10 +46,9 @@ public class AuthController { | |||
| public ApiResponse login(@Valid @RequestBody LoginRequest loginRequest) { | |||
| Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsernameOrEmailOrPhone(), loginRequest.getPassword())); | |||
| SecurityContextHolder.getContext() | |||
| .setAuthentication(authentication); | |||
| SecurityContextHolder.getContext().setAuthentication(authentication); | |||
| String jwt = jwtUtil.createJWT(authentication,loginRequest.getRememberMe()); | |||
| String jwt = jwtUtil.createJWT(authentication, loginRequest.getRememberMe()); | |||
| return ApiResponse.ofSuccess(new JwtResponse(jwt)); | |||
| } | |||
| @@ -53,7 +53,7 @@ public class MonitorController { | |||
| if (CollUtil.isEmpty(names)) { | |||
| throw new SecurityException(Status.PARAM_NOT_NULL); | |||
| } | |||
| if (names.contains(SecurityUtil.getCurrentUsername())){ | |||
| if (names.contains(SecurityUtil.getCurrentUsername())) { | |||
| throw new SecurityException(Status.KICKOUT_SELF); | |||
| } | |||
| monitorService.kickout(names); | |||
| @@ -42,14 +42,10 @@ public class GlobalExceptionHandler { | |||
| return ApiResponse.ofStatus(Status.HTTP_BAD_METHOD); | |||
| } else if (e instanceof MethodArgumentNotValidException) { | |||
| log.error("【全局异常拦截】MethodArgumentNotValidException", e); | |||
| return ApiResponse.of(Status.BAD_REQUEST.getCode(), ((MethodArgumentNotValidException) e).getBindingResult() | |||
| .getAllErrors() | |||
| .get(0) | |||
| .getDefaultMessage(), null); | |||
| return ApiResponse.of(Status.BAD_REQUEST.getCode(), ((MethodArgumentNotValidException) e).getBindingResult().getAllErrors().get(0).getDefaultMessage(), null); | |||
| } else if (e instanceof ConstraintViolationException) { | |||
| log.error("【全局异常拦截】ConstraintViolationException", e); | |||
| return ApiResponse.of(Status.BAD_REQUEST.getCode(), CollUtil.getFirst(((ConstraintViolationException) e).getConstraintViolations()) | |||
| .getMessage(), null); | |||
| return ApiResponse.of(Status.BAD_REQUEST.getCode(), CollUtil.getFirst(((ConstraintViolationException) e).getConstraintViolations()).getMessage(), null); | |||
| } else if (e instanceof MethodArgumentTypeMismatchException) { | |||
| log.error("【全局异常拦截】MethodArgumentTypeMismatchException: 参数名 {}, 异常信息 {}", ((MethodArgumentTypeMismatchException) e).getName(), ((MethodArgumentTypeMismatchException) e).getMessage()); | |||
| return ApiResponse.ofStatus(Status.PARAM_NOT_MATCH); | |||
| @@ -37,12 +37,9 @@ public class CustomUserDetailsService implements UserDetailsService { | |||
| @Override | |||
| public UserDetails loadUserByUsername(String usernameOrEmailOrPhone) throws UsernameNotFoundException { | |||
| User user = userDao.findByUsernameOrEmailOrPhone(usernameOrEmailOrPhone, usernameOrEmailOrPhone, usernameOrEmailOrPhone) | |||
| .orElseThrow(() -> new UsernameNotFoundException("未找到用户信息 : " + usernameOrEmailOrPhone)); | |||
| User user = userDao.findByUsernameOrEmailOrPhone(usernameOrEmailOrPhone, usernameOrEmailOrPhone, usernameOrEmailOrPhone).orElseThrow(() -> new UsernameNotFoundException("未找到用户信息 : " + usernameOrEmailOrPhone)); | |||
| List<Role> roles = roleDao.selectByUserId(user.getId()); | |||
| List<Long> roleIds = roles.stream() | |||
| .map(Role::getId) | |||
| .collect(Collectors.toList()); | |||
| List<Long> roleIds = roles.stream().map(Role::getId).collect(Collectors.toList()); | |||
| List<Permission> permissions = permissionDao.selectByRoleIdList(roleIds); | |||
| return UserPrincipal.create(user, roles, permissions); | |||
| } | |||
| @@ -46,9 +46,7 @@ public class MonitorService { | |||
| Long total = keys.getTotal(); | |||
| // 根据 redis 中键获取用户名列表 | |||
| List<String> usernameList = rows.stream() | |||
| .map(s -> StrUtil.subAfter(s, Consts.REDIS_JWT_KEY_PREFIX, true)) | |||
| .collect(Collectors.toList()); | |||
| List<String> usernameList = rows.stream().map(s -> StrUtil.subAfter(s, Consts.REDIS_JWT_KEY_PREFIX, true)).collect(Collectors.toList()); | |||
| // 根据用户名查询用户信息 | |||
| List<User> userList = userDao.findByUsernameIn(usernameList); | |||
| @@ -66,19 +64,16 @@ public class MonitorService { | |||
| */ | |||
| public void kickout(List<String> names) { | |||
| // 清除 Redis 中的 JWT 信息 | |||
| List<String> redisKeys = names.parallelStream() | |||
| .map(s -> Consts.REDIS_JWT_KEY_PREFIX + s) | |||
| .collect(Collectors.toList()); | |||
| List<String> redisKeys = names.parallelStream().map(s -> Consts.REDIS_JWT_KEY_PREFIX + s).collect(Collectors.toList()); | |||
| redisUtil.delete(redisKeys); | |||
| // 获取当前用户名 | |||
| String currentUsername = SecurityUtil.getCurrentUsername(); | |||
| names.parallelStream() | |||
| .forEach(name -> { | |||
| // TODO: 通知被踢出的用户已被当前登录用户踢出, | |||
| // 后期考虑使用 websocket 实现,具体伪代码实现如下。 | |||
| // String message = "您已被用户【" + currentUsername + "】手动下线!"; | |||
| log.debug("用户【{}】被用户【{}】手动下线!", name, currentUsername); | |||
| }); | |||
| names.parallelStream().forEach(name -> { | |||
| // TODO: 通知被踢出的用户已被当前登录用户踢出, | |||
| // 后期考虑使用 websocket 实现,具体伪代码实现如下。 | |||
| // String message = "您已被用户【" + currentUsername + "】手动下线!"; | |||
| log.debug("用户【{}】被用户【{}】手动下线!", name, currentUsername); | |||
| }); | |||
| } | |||
| } | |||
| @@ -53,13 +53,7 @@ public class JwtUtil { | |||
| */ | |||
| public String createJWT(Boolean rememberMe, Long id, String subject, List<String> roles, Collection<? extends GrantedAuthority> authorities) { | |||
| Date now = new Date(); | |||
| JwtBuilder builder = Jwts.builder() | |||
| .setId(id.toString()) | |||
| .setSubject(subject) | |||
| .setIssuedAt(now) | |||
| .signWith(SignatureAlgorithm.HS256, jwtConfig.getKey()) | |||
| .claim("roles", roles) | |||
| .claim("authorities", authorities); | |||
| JwtBuilder builder = Jwts.builder().setId(id.toString()).setSubject(subject).setIssuedAt(now).signWith(SignatureAlgorithm.HS256, jwtConfig.getKey()).claim("roles", roles).claim("authorities", authorities); | |||
| // 设置过期时间 | |||
| Long ttl = rememberMe ? jwtConfig.getRemember() : jwtConfig.getTtl(); | |||
| @@ -69,8 +63,7 @@ public class JwtUtil { | |||
| String jwt = builder.compact(); | |||
| // 将生成的JWT保存至Redis | |||
| stringRedisTemplate.opsForValue() | |||
| .set(Consts.REDIS_JWT_KEY_PREFIX + subject, jwt, ttl, TimeUnit.MILLISECONDS); | |||
| stringRedisTemplate.opsForValue().set(Consts.REDIS_JWT_KEY_PREFIX + subject, jwt, ttl, TimeUnit.MILLISECONDS); | |||
| return jwt; | |||
| } | |||
| @@ -94,10 +87,7 @@ public class JwtUtil { | |||
| */ | |||
| public Claims parseJWT(String jwt) { | |||
| try { | |||
| Claims claims = Jwts.parser() | |||
| .setSigningKey(jwtConfig.getKey()) | |||
| .parseClaimsJws(jwt) | |||
| .getBody(); | |||
| Claims claims = Jwts.parser().setSigningKey(jwtConfig.getKey()).parseClaimsJws(jwt).getBody(); | |||
| String username = claims.getSubject(); | |||
| String redisKey = Consts.REDIS_JWT_KEY_PREFIX + username; | |||
| @@ -109,8 +99,7 @@ public class JwtUtil { | |||
| } | |||
| // 校验redis中的JWT是否与当前的一致,不一致则代表用户已注销/用户在不同设备登录,均代表JWT已过期 | |||
| String redisToken = stringRedisTemplate.opsForValue() | |||
| .get(redisKey); | |||
| String redisToken = stringRedisTemplate.opsForValue().get(redisKey); | |||
| if (!StrUtil.equals(jwt, redisToken)) { | |||
| throw new SecurityException(Status.TOKEN_OUT_OF_CTRL); | |||
| } | |||
| @@ -38,9 +38,7 @@ public class RedisUtil { | |||
| * @return 分页获取指定格式key | |||
| */ | |||
| public PageResult<String> findKeysForPage(String patternKey, int currentPage, int pageSize) { | |||
| ScanOptions options = ScanOptions.scanOptions() | |||
| .match(patternKey) | |||
| .build(); | |||
| ScanOptions options = ScanOptions.scanOptions().match(patternKey).build(); | |||
| RedisConnectionFactory factory = stringRedisTemplate.getConnectionFactory(); | |||
| RedisConnection rc = factory.getConnection(); | |||
| Cursor<byte[]> cursor = rc.scan(options); | |||
| @@ -37,8 +37,7 @@ public class ResponseUtil { | |||
| // FIXME: hutool 的 BUG:JSONUtil.toJsonStr() | |||
| // 将JSON转为String的时候,忽略null值的时候转成的String存在错误 | |||
| response.getWriter() | |||
| .write(JSONUtil.toJsonStr(new JSONObject(ApiResponse.ofStatus(status, data), false))); | |||
| response.getWriter().write(JSONUtil.toJsonStr(new JSONObject(ApiResponse.ofStatus(status, data), false))); | |||
| } catch (IOException e) { | |||
| log.error("Response写出JSON异常,", e); | |||
| } | |||
| @@ -59,8 +58,7 @@ public class ResponseUtil { | |||
| // FIXME: hutool 的 BUG:JSONUtil.toJsonStr() | |||
| // 将JSON转为String的时候,忽略null值的时候转成的String存在错误 | |||
| response.getWriter() | |||
| .write(JSONUtil.toJsonStr(new JSONObject(ApiResponse.ofException(exception), false))); | |||
| response.getWriter().write(JSONUtil.toJsonStr(new JSONObject(ApiResponse.ofException(exception), false))); | |||
| } catch (IOException e) { | |||
| log.error("Response写出JSON异常,", e); | |||
| } | |||
| @@ -31,9 +31,7 @@ public class SecurityUtil { | |||
| * @return 当前登录用户信息,匿名登录时,为null | |||
| */ | |||
| public static UserPrincipal getCurrentUser() { | |||
| Object userInfo = SecurityContextHolder.getContext() | |||
| .getAuthentication() | |||
| .getPrincipal(); | |||
| Object userInfo = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); | |||
| if (userInfo instanceof UserDetails) { | |||
| return (UserPrincipal) userInfo; | |||
| } | |||