├── .gitignore ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── README.md ├── pom.xml └── src └── main ├── java └── com │ └── wpp │ └── devtools │ ├── DevtoolsApplication.java │ ├── config │ ├── BaiduConfig.java │ ├── CommonConfig.java │ ├── JWTConfig.java │ ├── RedisKeyConfig.java │ └── UrlConfig.java │ ├── controller │ ├── DevtoolsController.java │ ├── GameController.java │ ├── UnAuthController.java │ └── UserController.java │ ├── domain │ ├── annotation │ │ └── AccessLimit.java │ ├── bo │ │ ├── AddSubscribeBo.java │ │ ├── ForgetPasswordBo.java │ │ ├── GameEndBo.java │ │ ├── LoginBo.java │ │ ├── NotebookBo.java │ │ ├── PlayGameBo.java │ │ ├── RegisterBo.java │ │ └── SaveUserInfoBo.java │ ├── entity │ │ ├── Activity.java │ │ ├── DogText.java │ │ ├── EveryDayText.java │ │ ├── GameRecord.java │ │ ├── Notebook.java │ │ ├── Subscribe.java │ │ ├── SubscribeRecord.java │ │ ├── TextBoard.java │ │ ├── TextBoardPraise.java │ │ ├── User.java │ │ └── VerificationCode.java │ ├── enums │ │ ├── GameEnum.java │ │ └── TypeEnum.java │ ├── pojo │ │ └── Result.java │ └── vo │ │ ├── ResultVo.java │ │ └── UserVo.java │ ├── enums │ ├── ExceptionCodeEnums.java │ └── UserCodeEnums.java │ ├── exception │ ├── CustomException.java │ └── ExceptionAdvice.java │ ├── model │ ├── Cros.java │ ├── FilterInterceptor.java │ ├── JWTInterceptor.java │ ├── Schedule.java │ ├── Swagger.java │ └── WebConfiguration.java │ ├── repository │ ├── ActivityRepository.java │ ├── DogTextRepository.java │ ├── EveryDayTextRepository.java │ ├── GameRecordRepository.java │ ├── NotebookRepository.java │ ├── SubscribeRecordRepository.java │ ├── SubscribeRepository.java │ ├── TextBoardPraiseRepository.java │ ├── TextBoardRepository.java │ ├── UserRepository.java │ └── VerificationCodeRepository.java │ ├── service │ ├── DevtoolsService.java │ ├── GameService.java │ ├── UnAuthService.java │ └── UserService.java │ └── util │ ├── CommonUtils.java │ ├── EmailUtil.java │ ├── HttpUtil.java │ ├── JWTUtil.java │ ├── JpaUpdateUtil.java │ ├── MD5Util.java │ ├── RedistUtil.java │ └── SSLUtil.java └── resources ├── application.yml └── logback-spring.xml /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | 30 | ### VS Code ### 31 | .vscode/ 32 | /logs 33 | /src/main/resources/application-prod.yml 34 | /src/main/resources/application-test.yml 35 | /src/main/resources/application-dev.yml 36 | -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-present the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific volvo governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import java.util.Properties; 18 | 19 | public class MavenWrapperDownloader { 20 | 21 | private static final String WRAPPER_VERSION = "0.5.6"; 22 | /** 23 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 24 | */ 25 | private static final String DEFAULT_DOWNLOAD_URL = 26 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 27 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 28 | 29 | /** 30 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to use 31 | * instead of the default one. 32 | */ 33 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 34 | ".mvn/wrapper/maven-wrapper.properties"; 35 | 36 | /** 37 | * Path where the maven-wrapper.jar will be saved to. 38 | */ 39 | private static final String MAVEN_WRAPPER_JAR_PATH = 40 | ".mvn/wrapper/maven-wrapper.jar"; 41 | 42 | /** 43 | * Name of the property which should be used to override the default download url for the 44 | * wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if (mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if (mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if (!outputFile.getParentFile().exists()) { 80 | if (!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile() 83 | .getAbsolutePath() + "'"); 84 | } 85 | } 86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 87 | try { 88 | downloadFileFromURL(url, outputFile); 89 | System.out.println("Done"); 90 | System.exit(0); 91 | } catch (Throwable e) { 92 | System.out.println("- Error downloading"); 93 | e.printStackTrace(); 94 | System.exit(1); 95 | } 96 | } 97 | 98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 100 | String username = System.getenv("MVNW_USERNAME"); 101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 102 | Authenticator.setDefault(new Authenticator() { 103 | @Override 104 | protected PasswordAuthentication getPasswordAuthentication() { 105 | return new PasswordAuthentication(username, password); 106 | } 107 | }); 108 | } 109 | URL website = new URL(urlString); 110 | ReadableByteChannel rbc; 111 | rbc = Channels.newChannel(website.openStream()); 112 | FileOutputStream fos = new FileOutputStream(destination); 113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 114 | fos.close(); 115 | rbc.close(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangpinpin/devtools-server/95a425361931c6c6084bf37e7052a8f66624d1fd/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 网站内容: 常用开发工具、开放API等 2 | 3 | 本项目完全开源, 项目持续更新中 4 | 5 | 后端: Spring Boot 6 | 7 | 前端: Vue 8 | 9 | 前端项目地址: https://github.com/wangpinpin/devtools 10 | 11 | 12 | 13 | 14 | 目前功能: 舔狗日记、听歌音乐抖动粒子、每日一文、壁纸、网易云API、JSON格式化、二维码生成、颜色转换、图片文字提取 15 | 16 | 17 | 18 | 19 | 在线地址: https://wangpinpin.com/ 服务器到期了,没钱搞了 20 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.3.1.RELEASE 10 | 11 | 12 | devtools-server 13 | jar 14 | com.wpp 15 | devtools-sever 16 | 0.0.1-SNAPSHOT 17 | Demo project for Spring Boot 18 | 19 | 20 | 1.8 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-data-jpa 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-web 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-mail 35 | 36 | 37 | mysql 38 | mysql-connector-java 39 | runtime 40 | 41 | 42 | org.projectlombok 43 | lombok 44 | true 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-test 49 | test 50 | 51 | 52 | org.junit.vintage 53 | junit-vintage-engine 54 | 55 | 56 | 57 | 58 | 59 | 60 | io.swagger 61 | swagger-annotations 62 | 1.5.21 63 | 64 | 65 | io.swagger 66 | swagger-models 67 | 1.5.21 68 | 69 | 70 | io.springfox 71 | springfox-swagger2 72 | 2.8.0 73 | 74 | 75 | 76 | io.springfox 77 | springfox-swagger-ui 78 | 2.8.0 79 | 80 | 81 | com.github.xiaoymin 82 | swagger-bootstrap-ui 83 | 1.9.6 84 | 85 | 86 | 87 | io.jsonwebtoken 88 | jjwt 89 | 0.9.1 90 | 91 | 92 | 93 | 94 | com.alibaba 95 | fastjson 96 | 1.2.68 97 | 98 | 99 | org.hibernate 100 | hibernate-validator 101 | 6.0.17.Final 102 | 103 | 104 | javax.mail 105 | mail 106 | 1.4.7 107 | 108 | 109 | 110 | 111 | com.sun.mail 112 | javax.mail 113 | 1.6.2 114 | 115 | 116 | 117 | 118 | org.apache.commons 119 | commons-email 120 | 1.5 121 | 122 | 123 | 124 | com.aliyun.oss 125 | aliyun-sdk-oss 126 | 3.10.2 127 | 128 | 129 | 130 | org.springframework.boot 131 | spring-boot-starter-logging 132 | 133 | 134 | org.apache.commons 135 | commons-lang3 136 | 3.9 137 | 138 | 139 | org.springframework.boot 140 | spring-boot-starter-data-redis 141 | 142 | 143 | commons-io 144 | commons-io 145 | 2.6 146 | 147 | 148 | com.thoughtworks.xstream 149 | xstream 150 | 1.4.10 151 | 152 | 153 | 154 | org.jsoup 155 | jsoup 156 | 1.11.3 157 | 158 | 159 | 160 | 161 | 162 | devtools-server 163 | 164 | 165 | org.springframework.boot 166 | spring-boot-maven-plugin 167 | 2.2.2.RELEASE 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/DevtoolsApplication.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools; 2 | 3 | import com.alibaba.fastjson.PropertyNamingStrategy; 4 | import com.alibaba.fastjson.parser.ParserConfig; 5 | import java.net.InetAddress; 6 | import java.net.UnknownHostException; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.boot.SpringApplication; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | import org.springframework.core.env.Environment; 11 | import org.springframework.transaction.annotation.EnableTransactionManagement; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | 14 | @Slf4j 15 | @SpringBootApplication 16 | @EnableSwagger2 17 | @EnableTransactionManagement 18 | public class DevtoolsApplication { 19 | 20 | public static void main(String[] args) { 21 | 22 | //全局转JSON转驼峰 23 | ParserConfig.getGlobalInstance().propertyNamingStrategy = PropertyNamingStrategy.CamelCase; 24 | 25 | SpringApplication app = new SpringApplication(DevtoolsApplication.class); 26 | Environment env = app.run(args).getEnvironment(); 27 | String protocol = "http"; 28 | 29 | try { 30 | log.info("\n----------------------------------------------------------\n\t" + 31 | "Application '{}' is running! Access URLs:\n\t" + 32 | "Local: \t\t{}://localhost:{}\n\t" + 33 | "External: \t{}://{}:{}\n\t" + 34 | "swagger: \t{}://localhost:{}/swagger-ui.html\n----------------------------------------------------------", 35 | env.getProperty("spring.application.name"), 36 | protocol, 37 | env.getProperty("server.port"), 38 | protocol, 39 | InetAddress.getLocalHost().getHostAddress(), 40 | env.getProperty("server.port"), 41 | protocol, 42 | env.getProperty("server.port")); 43 | } catch (UnknownHostException e) { 44 | e.printStackTrace(); 45 | } 46 | 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/config/BaiduConfig.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | @Data 9 | public class BaiduConfig { 10 | 11 | @Value("${BAIDU.APP_ID}") 12 | private String appId; 13 | 14 | @Value("${BAIDU.API_KEY}") 15 | private String apiKey; 16 | 17 | @Value("${BAIDU.SECRET_KEY}") 18 | private String secretKey; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/config/CommonConfig.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.config; 2 | 3 | /** 4 | * @program: volvo-server 5 | * @description: 6 | * @author: wpp 7 | * @create: 2020-07-28 8 | **/ 9 | public class CommonConfig { 10 | 11 | public final static String PASSWORD_VALIDATE = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,18}$"; 12 | 13 | //https://alapi.net/ token 14 | public final static String ALAPI_TOKEN = "yKxNvBtSS5UyrjhzjFWl"; 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/config/JWTConfig.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | * @program: devtools-server 9 | * @description: 10 | * @author: wpp 11 | * @create: 2020-07-06 12 | **/ 13 | @Component 14 | @Data 15 | public class JWTConfig { 16 | 17 | @Value("${JWT.JWT_CLIENTID}") 18 | private String jwtClientid; 19 | 20 | @Value("${JWT.JWT_BASE64SECRET}") 21 | private String jwtBase64secret; 22 | 23 | public final static String JWT_NAME = "xiaopozhan"; 24 | 25 | public final static long JWT_EXPIRESSECOND = 9999999999L; //永久 26 | 27 | public final static String JWT_BEARER = "Bearer"; 28 | 29 | public final static String JWT_HEADER = "Authorization"; 30 | 31 | public final static String JWT_USER_ID_KEY = "USERID"; 32 | 33 | } -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/config/RedisKeyConfig.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.config; 2 | 3 | /** 4 | * @program: devtools-server 5 | * @description: 6 | * @author: wpp 7 | * @create: 2020-08-05 8 | **/ 9 | public class RedisKeyConfig { 10 | 11 | public static final String BAIDU_ACCESS_TOKEN_KEY = "BAIDU_ACCESS_TOKEN_KEY"; 12 | public static final String COUNT = "count"; 13 | public static final String WARNING = "WARNING"; 14 | public static final String BLACKLIST = "BLACKLIST"; 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/config/UrlConfig.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.config; 2 | 3 | public class UrlConfig { 4 | 5 | public static final String DOG_LICKING_DIARY_URL = "https://v1.alapi.cn/api/dog"; 6 | 7 | public static final String ENERY_DAY_TEXT = "https://v1.alapi.cn/api/mryw/random"; 8 | 9 | public static final String BAIDU_ACCESS_TOKEN_URL = "https://aip.baidubce.com/oauth/2.0/token"; 10 | 11 | public static final String BAIDU_IMG_TO_TEXT_URL = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?access_token={0}"; 12 | 13 | public static final String HEFENG_WEATHER_NOW_URL = "https://devapi.heweather.net/v7/weather/now?location={0}&key={1}&gzip=n"; 14 | 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/controller/DevtoolsController.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.controller; 2 | 3 | import com.wpp.devtools.domain.pojo.Result; 4 | import com.wpp.devtools.domain.vo.ResultVo; 5 | import com.wpp.devtools.service.DevtoolsService; 6 | import io.swagger.annotations.Api; 7 | import io.swagger.annotations.ApiOperation; 8 | import javax.servlet.http.HttpServletRequest; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RequestParam; 13 | import org.springframework.web.bind.annotation.RestController; 14 | import org.springframework.web.multipart.MultipartFile; 15 | 16 | @RestController 17 | @RequestMapping("/devTools/") 18 | @Api(tags = {"工具接口服务"}) 19 | public class DevtoolsController { 20 | 21 | 22 | @Autowired 23 | private HttpServletRequest request; 24 | 25 | @Autowired 26 | private DevtoolsService devtoolsService; 27 | 28 | @ApiOperation("图片转base64") 29 | @PostMapping("imgToBase64") 30 | public Result imgToBase64(@RequestParam MultipartFile file) { 31 | return ResultVo.success(devtoolsService.imgToBase64(file)); 32 | } 33 | 34 | @ApiOperation("图片加水印") 35 | @PostMapping("imgAddWatermark") 36 | public Result imgAddWatermark(@RequestParam MultipartFile file) { 37 | return ResultVo.success(devtoolsService.imgAddWatermark(file)); 38 | } 39 | 40 | @ApiOperation("图片去水印") 41 | @PostMapping("imgClearWatermark") 42 | public Result imgClearWatermark(@RequestParam MultipartFile file, @RequestParam String backgroundColor, @RequestParam String watermarkColor, @RequestParam int precision) { 43 | return ResultVo.success(devtoolsService.imgClearWatermark(file, backgroundColor, watermarkColor, precision)); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/controller/GameController.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.controller; 2 | 3 | import com.wpp.devtools.config.JWTConfig; 4 | import com.wpp.devtools.domain.bo.GameEndBo; 5 | import com.wpp.devtools.domain.bo.PlayGameBo; 6 | import com.wpp.devtools.domain.pojo.Result; 7 | import com.wpp.devtools.domain.vo.ResultVo; 8 | import com.wpp.devtools.service.GameService; 9 | import com.wpp.devtools.util.CommonUtils; 10 | import io.swagger.annotations.Api; 11 | import io.swagger.annotations.ApiOperation; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.validation.annotation.Validated; 14 | import org.springframework.web.bind.annotation.*; 15 | import org.springframework.web.multipart.MultipartFile; 16 | 17 | import javax.servlet.http.HttpServletRequest; 18 | 19 | @RestController 20 | @RequestMapping("/game/") 21 | @Api(tags = {"游戏接口服务"}) 22 | public class GameController { 23 | 24 | @Autowired 25 | private GameService gameService; 26 | 27 | @Autowired 28 | private HttpServletRequest request; 29 | 30 | 31 | @ApiOperation("游戏开始接口") 32 | @PostMapping("playGame") 33 | public Result playGame(@Validated @RequestBody PlayGameBo playGameBo) { 34 | Object userJwt = request.getAttribute(JWTConfig.JWT_USER_ID_KEY); 35 | String userId = userJwt == null ? null : userJwt.toString(); 36 | 37 | gameService.playGame(playGameBo, userId); 38 | return ResultVo.success(); 39 | } 40 | 41 | @ApiOperation("游戏结束接口") 42 | @PostMapping("gameEnd") 43 | public Result gameEnd() { 44 | Object userJwt = request.getAttribute(JWTConfig.JWT_USER_ID_KEY); 45 | String userId = userJwt == null ? null : userJwt.toString(); 46 | 47 | gameService.gameEnd(userId); 48 | return ResultVo.success(); 49 | } 50 | 51 | @ApiOperation("游戏排行榜查询") 52 | @PostMapping("gameRank/{gameCode}") 53 | public Result gameRank(@PathVariable String gameCode) { 54 | return ResultVo.success(gameService.gameRank(gameCode)); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/controller/UnAuthController.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.controller; 2 | 3 | import com.wpp.devtools.config.JWTConfig; 4 | import com.wpp.devtools.domain.annotation.AccessLimit; 5 | import com.wpp.devtools.domain.bo.ForgetPasswordBo; 6 | import com.wpp.devtools.domain.bo.LoginBo; 7 | import com.wpp.devtools.domain.bo.RegisterBo; 8 | import com.wpp.devtools.domain.enums.TypeEnum; 9 | import com.wpp.devtools.domain.pojo.Result; 10 | import com.wpp.devtools.domain.vo.ResultVo; 11 | import com.wpp.devtools.service.UnAuthService; 12 | import com.wpp.devtools.service.UserService; 13 | import com.wpp.devtools.util.CommonUtils; 14 | import io.swagger.annotations.Api; 15 | import io.swagger.annotations.ApiOperation; 16 | 17 | import java.util.List; 18 | import javax.servlet.http.HttpServletRequest; 19 | import javax.validation.Valid; 20 | 21 | import org.apache.commons.lang3.StringUtils; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.web.bind.annotation.GetMapping; 24 | import org.springframework.web.bind.annotation.PostMapping; 25 | import org.springframework.web.bind.annotation.RequestBody; 26 | import org.springframework.web.bind.annotation.RequestMapping; 27 | import org.springframework.web.bind.annotation.RequestParam; 28 | import org.springframework.web.bind.annotation.RestController; 29 | import org.springframework.web.multipart.MultipartFile; 30 | 31 | @RestController 32 | @RequestMapping("/unAuth/") 33 | @Api(tags = {"无权限接口服务"}) 34 | public class UnAuthController { 35 | 36 | 37 | @Autowired 38 | private HttpServletRequest request; 39 | 40 | @Autowired 41 | private UnAuthService unAuthService; 42 | 43 | @Autowired 44 | private UserService userService; 45 | 46 | @ApiOperation("舔狗日记") 47 | @GetMapping("getDoglickingDiary") 48 | @AccessLimit(seconds = 10, maxCount = 10) 49 | public Result getDoglickingDiary() { 50 | return ResultVo.success(unAuthService.getDoglickingDiary()); 51 | } 52 | 53 | 54 | @ApiOperation("每日一文添加") 55 | @GetMapping("addEveryDayText") 56 | public Result addEveryDayText() { 57 | unAuthService.addEveryDayText(); 58 | return ResultVo.success(); 59 | } 60 | 61 | @ApiOperation("每日一文") 62 | @GetMapping("getEveryDayText") 63 | @AccessLimit(seconds = 10, maxCount = 5) 64 | public Result getEveryDayText() { 65 | return ResultVo.success(unAuthService.getEveryDayText()); 66 | } 67 | 68 | @ApiOperation("图片转文字") 69 | @PostMapping("imgToText") 70 | public Result imgToText(@RequestParam MultipartFile file) { 71 | return ResultVo.success(unAuthService.imgToText(file)); 72 | } 73 | 74 | @ApiOperation("同步舔狗日记") 75 | @PostMapping("getDoglickingDiaryListInsert") 76 | public Result getDoglickingDiaryListInsert() { 77 | try { 78 | unAuthService.getDoglickingDiaryListInsert(); 79 | } catch (InterruptedException e) { 80 | e.printStackTrace(); 81 | } 82 | return ResultVo.success(); 83 | } 84 | 85 | @PostMapping("addGogText") 86 | public Result addGogText(@RequestBody List texts) { 87 | return ResultVo.success(unAuthService.addGogText(texts)); 88 | } 89 | 90 | @ApiOperation("添加留言") 91 | @PostMapping("addMsgBoard") 92 | @AccessLimit(seconds = 5, maxCount = 2) 93 | public Result addMsgBoard(@RequestParam String msg, String msgId) { 94 | String userId = request.getAttribute(JWTConfig.JWT_USER_ID_KEY).toString(); 95 | if (StringUtils.isBlank(userId)) { 96 | userId = CommonUtils.getIpAddr(request); 97 | } 98 | unAuthService.addMsgBoard(msg, msgId, userId); 99 | return ResultVo.success(); 100 | } 101 | 102 | @ApiOperation("查询留言列表") 103 | @GetMapping("findMsgBoard") 104 | public Result findMsgBoard(int pageNo, int pageSize) { 105 | Object userJwt = request.getAttribute(JWTConfig.JWT_USER_ID_KEY); 106 | String userId = userJwt == null ? CommonUtils.getIpAddr(request) : userJwt.toString(); 107 | 108 | return ResultVo.success(unAuthService.findMsgBoard(pageNo, pageSize, userId)); 109 | } 110 | 111 | @ApiOperation("留言点赞") 112 | @PostMapping("msgBoardPraise") 113 | public Result msgBoardPraise(@RequestParam String msgId) { 114 | Object userJwt = request.getAttribute(JWTConfig.JWT_USER_ID_KEY); 115 | String userId = userJwt == null ? CommonUtils.getIpAddr(request) : userJwt.toString(); 116 | 117 | unAuthService.msgBoardPraise(msgId, userId); 118 | return ResultVo.success(); 119 | } 120 | 121 | @ApiOperation("跨域接口") 122 | @GetMapping("crossDomain") 123 | public Result crossDomain(@RequestParam String url) { 124 | return ResultVo.success(unAuthService.crossDomain(url)); 125 | } 126 | 127 | @ApiOperation("验证邮箱是否存在") 128 | @GetMapping("emailIsExist") 129 | public Result emailIsExist(@RequestParam String email) { 130 | return ResultVo.success(unAuthService.emailIsExist(email)); 131 | } 132 | 133 | @ApiOperation("发送验证码") 134 | @PostMapping("sendCode") 135 | @AccessLimit(seconds = 60, maxCount = 3) 136 | public Result sendCode(@RequestParam String email) { 137 | unAuthService.sendCode(email); 138 | return ResultVo.success(); 139 | } 140 | 141 | @ApiOperation("注册") 142 | @PostMapping("register") 143 | public Result register(@Valid @RequestBody RegisterBo r) { 144 | unAuthService.register(r); 145 | return ResultVo.success(); 146 | } 147 | 148 | @ApiOperation("登录") 149 | @PostMapping("login") 150 | public Result login(@Valid @RequestBody LoginBo l) { 151 | return ResultVo.success(unAuthService.login(l)); 152 | } 153 | 154 | @ApiOperation("忘记密码") 155 | @PostMapping("forgetPassword") 156 | public Result forgetPassword(@Valid @RequestBody ForgetPasswordBo f) { 157 | unAuthService.forgetPassword(f); 158 | return ResultVo.success(); 159 | } 160 | 161 | @ApiOperation("取消订阅") 162 | @PostMapping("cancelSubscribe") 163 | public Result sendSubscribe(@RequestParam String id, @RequestParam Boolean cancel) { 164 | userService.cancelSubscribe(id, cancel); 165 | return ResultVo.success(); 166 | } 167 | 168 | @ApiOperation("查询实况天气") 169 | @GetMapping("findWeatherNow") 170 | public Result findWeatherNow(@RequestParam String weatherId) { 171 | return ResultVo.success(unAuthService.findWeatherNow(weatherId)); 172 | } 173 | 174 | } 175 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.controller; 2 | 3 | import com.wpp.devtools.config.JWTConfig; 4 | import com.wpp.devtools.domain.bo.AddSubscribeBo; 5 | import com.wpp.devtools.domain.bo.NotebookBo; 6 | import com.wpp.devtools.domain.bo.SaveUserInfoBo; 7 | import com.wpp.devtools.domain.pojo.Result; 8 | import com.wpp.devtools.domain.vo.ResultVo; 9 | import com.wpp.devtools.service.UserService; 10 | import io.swagger.annotations.Api; 11 | import io.swagger.annotations.ApiOperation; 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.validation.Valid; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.web.bind.annotation.GetMapping; 16 | import org.springframework.web.bind.annotation.PostMapping; 17 | import org.springframework.web.bind.annotation.RequestBody; 18 | import org.springframework.web.bind.annotation.RequestMapping; 19 | import org.springframework.web.bind.annotation.RequestParam; 20 | import org.springframework.web.bind.annotation.RestController; 21 | 22 | @RestController 23 | @RequestMapping("/user/") 24 | @Api(tags = {"用户接口服务"}) 25 | public class UserController { 26 | 27 | 28 | @Autowired 29 | private HttpServletRequest request; 30 | 31 | @Autowired 32 | private UserService userService; 33 | 34 | @ApiOperation("保存用户信息") 35 | @PostMapping("saveUserInfo") 36 | public Result saveUserInfo(@RequestBody SaveUserInfoBo u) { 37 | String userId = request.getAttribute(JWTConfig.JWT_USER_ID_KEY).toString(); 38 | userService.saveUserInfo(u, userId); 39 | return ResultVo.success(); 40 | } 41 | 42 | @ApiOperation("获取用户信息") 43 | @PostMapping("findUserInfo") 44 | public Result findUserInfo() { 45 | String userId = request.getAttribute(JWTConfig.JWT_USER_ID_KEY).toString(); 46 | return ResultVo.success(userService.findUserInfo(userId)); 47 | } 48 | 49 | @ApiOperation("查询活动列表") 50 | @GetMapping("findActivityList") 51 | public Result findActivityList() { 52 | return ResultVo.success(userService.findActivityList()); 53 | } 54 | 55 | @ApiOperation("添加订阅") 56 | @PostMapping("addSubscribe") 57 | public Result addSubscribe(@Valid @RequestBody AddSubscribeBo a) { 58 | String userId = request.getAttribute(JWTConfig.JWT_USER_ID_KEY).toString(); 59 | userService.addSubscribe(a, userId); 60 | return ResultVo.success(); 61 | } 62 | 63 | @ApiOperation("查询订阅") 64 | @GetMapping("findSubscribe") 65 | public Result findSubscribe() { 66 | String userId = request.getAttribute(JWTConfig.JWT_USER_ID_KEY).toString(); 67 | return ResultVo.success(userService.findSubscribe(userId)); 68 | } 69 | 70 | @ApiOperation("发送订阅") 71 | @PostMapping("sendSubscribe") 72 | public Result sendSubscribe() { 73 | userService.sendSubscribe(); 74 | return ResultVo.success(); 75 | } 76 | 77 | @ApiOperation("启用禁用订阅") 78 | @PostMapping("enabledSubscribe") 79 | public Result enabledSubscribe(@RequestParam String id, @RequestParam Boolean enabled) { 80 | userService.enabledSubscribe(id, enabled); 81 | return ResultVo.success(); 82 | } 83 | 84 | @ApiOperation("删除订阅") 85 | @PostMapping("delSubscribe") 86 | public Result delSubscribe(@RequestParam String id) { 87 | userService.delSubscribe(id); 88 | return ResultVo.success(); 89 | } 90 | 91 | @ApiOperation("保存笔记") 92 | @PostMapping("saveNotebook") 93 | public Result saveNotebook(@RequestBody NotebookBo n) { 94 | String userId = request.getAttribute(JWTConfig.JWT_USER_ID_KEY).toString(); 95 | userService.saveNotebook(userId, n); 96 | return ResultVo.success(); 97 | } 98 | 99 | @ApiOperation("删除笔记") 100 | @PostMapping("delNotebook") 101 | public Result saveNotebook(@RequestParam String id) { 102 | userService.delNotebook(id); 103 | return ResultVo.success(); 104 | } 105 | 106 | @ApiOperation("查询笔记列表") 107 | @GetMapping("findNotebookList") 108 | public Result findNotebookList() { 109 | String userId = request.getAttribute(JWTConfig.JWT_USER_ID_KEY).toString(); 110 | return ResultVo.success(userService.findNotebookList(userId)); 111 | } 112 | 113 | @ApiOperation("修改笔记排序") 114 | @PostMapping("updateNotebookIndex") 115 | public Result updateNotebookIndex(@RequestParam String id, @RequestParam long oldIndex, @RequestParam long newIndex) { 116 | String userId = request.getAttribute(JWTConfig.JWT_USER_ID_KEY).toString(); 117 | userService.updateNotebookIndex(id, userId, oldIndex, newIndex); 118 | return ResultVo.success(); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/annotation/AccessLimit.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.annotation; 2 | 3 | import static java.lang.annotation.ElementType.METHOD; 4 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 5 | 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * @program: devtools-server 11 | * @description: 12 | * @author: wpp 13 | * @create: 2020-08-14 14 | **/ 15 | @Retention(RUNTIME) 16 | @Target(METHOD) 17 | public @interface AccessLimit { 18 | 19 | int seconds(); 20 | int maxCount(); 21 | } -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/bo/AddSubscribeBo.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.bo; 2 | 3 | import io.swagger.annotations.ApiModelProperty; 4 | import java.util.List; 5 | import javax.validation.constraints.NotBlank; 6 | import javax.validation.constraints.NotEmpty; 7 | import javax.validation.constraints.NotNull; 8 | import lombok.Data; 9 | 10 | /** 11 | * @program: devtools-server 12 | * @description: 13 | * @author: wpp 14 | * @create: 2020-09-17 15 | **/ 16 | @Data 17 | public class AddSubscribeBo { 18 | 19 | private String id; 20 | 21 | @ApiModelProperty("昵称") 22 | private String nickName; 23 | 24 | @ApiModelProperty("女神昵称") 25 | @NotBlank(message = "女神昵称不能为空") 26 | private String godNickName; 27 | 28 | @ApiModelProperty("邮箱") 29 | @NotBlank(message = "邮箱不能为空") 30 | private String email; 31 | 32 | @ApiModelProperty("发送时间 单位小时") 33 | @NotNull(message = "发送时间不能为空") 34 | private Integer hour; 35 | 36 | @ApiModelProperty("活动名称") 37 | @NotEmpty(message = "活动名称不能为空") 38 | private List activityName; 39 | 40 | @ApiModelProperty("是否启用") 41 | private boolean enabled; 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/bo/ForgetPasswordBo.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.bo; 2 | 3 | import com.wpp.devtools.config.CommonConfig; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import javax.validation.constraints.NotBlank; 6 | import javax.validation.constraints.Pattern; 7 | import lombok.Data; 8 | 9 | /** 10 | * @program: devtools-server 11 | * @description: 12 | * @author: wpp 13 | * @create: 2020-09-17 14 | **/ 15 | @Data 16 | public class ForgetPasswordBo { 17 | 18 | @ApiModelProperty("验证码") 19 | @NotBlank(message = "验证码不能为空") 20 | private String code; 21 | 22 | @NotBlank(message = "邮箱不能为空") 23 | @ApiModelProperty("邮箱") 24 | private String email; 25 | 26 | @NotBlank(message = "密码不能为空") 27 | @Pattern(regexp = CommonConfig.PASSWORD_VALIDATE, message = "密码必须同时包含字母数字的6-18位组合") 28 | @ApiModelProperty("密码") 29 | private String password; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/bo/GameEndBo.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.bo; 2 | 3 | import io.swagger.annotations.ApiModelProperty; 4 | import lombok.Data; 5 | 6 | import javax.validation.constraints.NotBlank; 7 | 8 | /** 9 | * @program: devtools-server 10 | * @description: 11 | * @author: wpp 12 | * @create: 2021-12-06 13 | **/ 14 | @Data 15 | public class GameEndBo { 16 | 17 | @NotBlank(message = "用户临时ID不能为空") 18 | @ApiModelProperty("用户临时ID") 19 | private String userUUID; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/bo/LoginBo.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.bo; 2 | 3 | import io.swagger.annotations.ApiModelProperty; 4 | import javax.validation.constraints.NotBlank; 5 | import lombok.Data; 6 | 7 | /** 8 | * @program: devtools-server 9 | * @description: 10 | * @author: wpp 11 | * @create: 2020-09-17 12 | **/ 13 | @Data 14 | public class LoginBo { 15 | 16 | @NotBlank(message = "邮箱不能为空") 17 | @ApiModelProperty("邮箱") 18 | private String email; 19 | 20 | @NotBlank(message = "密码不能为空") 21 | @ApiModelProperty("密码") 22 | private String password; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/bo/NotebookBo.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.bo; 2 | 3 | import io.swagger.annotations.ApiModelProperty; 4 | import lombok.Data; 5 | 6 | @Data 7 | public class NotebookBo { 8 | 9 | 10 | private String id; 11 | 12 | @ApiModelProperty("标题") 13 | private String title; 14 | 15 | @ApiModelProperty("内容") 16 | private String content; 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/bo/PlayGameBo.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.bo; 2 | 3 | import io.swagger.annotations.ApiModelProperty; 4 | import lombok.Data; 5 | 6 | import javax.validation.constraints.NotBlank; 7 | 8 | /** 9 | * @program: devtools-server 10 | * @description: 11 | * @author: wpp 12 | * @create: 2021-12-06 13 | **/ 14 | @Data 15 | public class PlayGameBo { 16 | 17 | @NotBlank(message = "游戏编号不能为空") 18 | @ApiModelProperty("游戏编号") 19 | private String gameCode; 20 | 21 | @NotBlank(message = "游戏等级不能为空") 22 | @ApiModelProperty("游戏等级") 23 | private String gameLevel; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/bo/RegisterBo.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.bo; 2 | 3 | import com.wpp.devtools.config.CommonConfig; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import javax.validation.constraints.NotBlank; 6 | import javax.validation.constraints.Pattern; 7 | import lombok.Data; 8 | 9 | /** 10 | * @program: devtools-server 11 | * @description: 12 | * @author: wpp 13 | * @create: 2020-09-17 14 | **/ 15 | @Data 16 | public class RegisterBo { 17 | 18 | @ApiModelProperty("验证码") 19 | @NotBlank(message = "验证码不能为空") 20 | private String code; 21 | 22 | @NotBlank(message = "邮箱不能为空") 23 | @ApiModelProperty("邮箱") 24 | private String email; 25 | 26 | @NotBlank(message = "密码不能为空") 27 | @Pattern(regexp = CommonConfig.PASSWORD_VALIDATE, message = "密码必须同时包含字母数字的6-18位组合") 28 | @ApiModelProperty("密码") 29 | private String password; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/bo/SaveUserInfoBo.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.bo; 2 | 3 | import io.swagger.annotations.ApiModelProperty; 4 | import java.util.List; 5 | import javax.validation.constraints.NotBlank; 6 | import javax.validation.constraints.NotEmpty; 7 | import javax.validation.constraints.NotNull; 8 | import lombok.Data; 9 | 10 | /** 11 | * @program: devtools-server 12 | * @description: 13 | * @author: wpp 14 | * @create: 2021-01-22 15 | **/ 16 | @Data 17 | public class SaveUserInfoBo { 18 | 19 | private String id; 20 | 21 | @ApiModelProperty("昵称") 22 | private String nickName; 23 | 24 | @ApiModelProperty("性别: 0 未知 1 男 2 女") 25 | private Integer gender; 26 | 27 | @ApiModelProperty("头像") 28 | private String headImg; 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/entity/Activity.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.entity; 2 | 3 | 4 | import javax.persistence.Entity; 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.Id; 7 | import javax.persistence.Table; 8 | import lombok.AllArgsConstructor; 9 | import lombok.Builder; 10 | import lombok.Data; 11 | import lombok.NoArgsConstructor; 12 | import org.hibernate.annotations.DynamicInsert; 13 | import org.hibernate.annotations.DynamicUpdate; 14 | import org.hibernate.annotations.GenericGenerator; 15 | 16 | @Data 17 | @Entity 18 | @Table(name = "activity") 19 | @Builder 20 | @AllArgsConstructor 21 | @NoArgsConstructor 22 | @DynamicUpdate 23 | @DynamicInsert 24 | @GenericGenerator(name = "jpa-uuid", strategy = "uuid") 25 | public class Activity { 26 | 27 | @Id 28 | @GeneratedValue(generator = "jpa-uuid") 29 | private String id; 30 | private String name; 31 | private long sort; 32 | private boolean enabled; 33 | private java.sql.Timestamp createTime; 34 | private java.sql.Timestamp updateTime; 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/entity/DogText.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.entity; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.GenerationType; 6 | import javax.persistence.Id; 7 | import javax.persistence.Table; 8 | import lombok.AllArgsConstructor; 9 | import lombok.Builder; 10 | import lombok.Data; 11 | import lombok.NoArgsConstructor; 12 | import org.hibernate.annotations.DynamicUpdate; 13 | 14 | @Data 15 | @Entity 16 | @Table(name = "dog_text") 17 | @Builder 18 | @AllArgsConstructor 19 | @NoArgsConstructor 20 | @DynamicUpdate 21 | public class DogText { 22 | 23 | @Id 24 | @GeneratedValue(strategy= GenerationType.IDENTITY) 25 | private long id; 26 | private String content; 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/entity/EveryDayText.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.entity; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.GenerationType; 6 | import javax.persistence.Id; 7 | import javax.persistence.Table; 8 | import lombok.AllArgsConstructor; 9 | import lombok.Builder; 10 | import lombok.Data; 11 | import lombok.NoArgsConstructor; 12 | import org.hibernate.annotations.DynamicUpdate; 13 | 14 | @Data 15 | @Entity 16 | @Table(name = "every_day_text") 17 | @Builder 18 | @AllArgsConstructor 19 | @NoArgsConstructor 20 | @DynamicUpdate 21 | public class EveryDayText { 22 | 23 | @Id 24 | @GeneratedValue(strategy= GenerationType.IDENTITY) 25 | private long id; 26 | private String author; 27 | private String title; 28 | private String content; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/entity/GameRecord.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | import org.hibernate.annotations.DynamicInsert; 8 | import org.hibernate.annotations.DynamicUpdate; 9 | import org.hibernate.annotations.GenericGenerator; 10 | 11 | import javax.persistence.Entity; 12 | import javax.persistence.GeneratedValue; 13 | import javax.persistence.Id; 14 | import javax.persistence.Table; 15 | 16 | @Data 17 | @Entity 18 | @Table(name = "game_record") 19 | @Builder 20 | @AllArgsConstructor 21 | @NoArgsConstructor 22 | @DynamicUpdate 23 | @DynamicInsert 24 | @GenericGenerator(name = "jpa-uuid", strategy = "uuid") 25 | public class GameRecord { 26 | 27 | @Id 28 | @GeneratedValue(generator = "jpa-uuid") 29 | private String id; 30 | private String userId; 31 | private String gameCode; 32 | private String gameLevel; 33 | private java.sql.Timestamp startTime; 34 | private java.sql.Timestamp endTime; 35 | private Long seconds; 36 | private java.sql.Timestamp createTime; 37 | private java.sql.Timestamp updateTime; 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/entity/Notebook.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.entity; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.Id; 6 | import javax.persistence.Table; 7 | import lombok.AllArgsConstructor; 8 | import lombok.Builder; 9 | import lombok.Data; 10 | import lombok.NoArgsConstructor; 11 | import org.hibernate.annotations.DynamicInsert; 12 | import org.hibernate.annotations.DynamicUpdate; 13 | import org.hibernate.annotations.GenericGenerator; 14 | 15 | @Data 16 | @Entity 17 | @Table(name = "notebook") 18 | @Builder 19 | @AllArgsConstructor 20 | @NoArgsConstructor 21 | @DynamicUpdate 22 | @DynamicInsert 23 | @GenericGenerator(name = "jpa-uuid", strategy = "uuid") 24 | public class Notebook { 25 | 26 | @Id 27 | @GeneratedValue(generator = "jpa-uuid") 28 | private String id; 29 | private String userId; 30 | private String title; 31 | private String content; 32 | private Long sort; 33 | private java.sql.Timestamp createTime; 34 | private java.sql.Timestamp updateTime; 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/entity/Subscribe.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.entity; 2 | 3 | 4 | import javax.persistence.Entity; 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.Id; 7 | import javax.persistence.Table; 8 | import lombok.AllArgsConstructor; 9 | import lombok.Builder; 10 | import lombok.Data; 11 | import lombok.NoArgsConstructor; 12 | import org.hibernate.annotations.DynamicInsert; 13 | import org.hibernate.annotations.DynamicUpdate; 14 | import org.hibernate.annotations.GenericGenerator; 15 | 16 | @Data 17 | @Entity 18 | @Table(name = "subscribe") 19 | @Builder 20 | @AllArgsConstructor 21 | @NoArgsConstructor 22 | @DynamicUpdate 23 | @DynamicInsert 24 | @GenericGenerator(name = "jpa-uuid", strategy = "uuid") 25 | public class Subscribe { 26 | 27 | @Id 28 | @GeneratedValue(generator = "jpa-uuid") 29 | private String id; 30 | private String userId; 31 | private String nickName; 32 | private String godNickName; 33 | private String email; 34 | private Integer hour; 35 | private String activityName; 36 | private boolean enabled; 37 | private boolean cancel; 38 | private java.sql.Timestamp createTime; 39 | private java.sql.Timestamp updateTime; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/entity/SubscribeRecord.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.entity; 2 | 3 | 4 | import javax.persistence.Entity; 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.Id; 7 | import javax.persistence.Table; 8 | import lombok.AllArgsConstructor; 9 | import lombok.Builder; 10 | import lombok.Data; 11 | import lombok.NoArgsConstructor; 12 | import org.hibernate.annotations.DynamicInsert; 13 | import org.hibernate.annotations.DynamicUpdate; 14 | import org.hibernate.annotations.GenericGenerator; 15 | 16 | @Data 17 | @Entity 18 | @Table(name = "subscribe_record") 19 | @Builder 20 | @AllArgsConstructor 21 | @NoArgsConstructor 22 | @DynamicUpdate 23 | @DynamicInsert 24 | @GenericGenerator(name = "jpa-uuid", strategy = "uuid") 25 | public class SubscribeRecord { 26 | 27 | @Id 28 | @GeneratedValue(generator = "jpa-uuid") 29 | private String id; 30 | private String subscribeId; 31 | private java.sql.Timestamp createTime; 32 | private java.sql.Timestamp updateTime; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/entity/TextBoard.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.entity; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.Id; 6 | import javax.persistence.Table; 7 | import lombok.AllArgsConstructor; 8 | import lombok.Builder; 9 | import lombok.Data; 10 | import lombok.NoArgsConstructor; 11 | import org.hibernate.annotations.DynamicInsert; 12 | import org.hibernate.annotations.DynamicUpdate; 13 | import org.hibernate.annotations.GenericGenerator; 14 | 15 | @Data 16 | @Entity 17 | @Table(name = "text_board") 18 | @Builder 19 | @AllArgsConstructor 20 | @NoArgsConstructor 21 | @DynamicUpdate 22 | @DynamicInsert 23 | @GenericGenerator(name = "jpa-uuid", strategy = "uuid") 24 | public class TextBoard { 25 | 26 | @Id 27 | @GeneratedValue(generator = "jpa-uuid") 28 | private String id; 29 | private String userId; 30 | private String content; 31 | private String parentId; 32 | private int praiseCount; 33 | private java.sql.Timestamp createTime; 34 | private java.sql.Timestamp updateTime; 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/entity/TextBoardPraise.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.entity; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.Id; 6 | import javax.persistence.Table; 7 | import lombok.AllArgsConstructor; 8 | import lombok.Builder; 9 | import lombok.Data; 10 | import lombok.NoArgsConstructor; 11 | import org.hibernate.annotations.DynamicInsert; 12 | import org.hibernate.annotations.DynamicUpdate; 13 | import org.hibernate.annotations.GenericGenerator; 14 | 15 | @Data 16 | @Entity 17 | @Table(name = "text_board_praise") 18 | @Builder 19 | @AllArgsConstructor 20 | @NoArgsConstructor 21 | @DynamicUpdate 22 | @DynamicInsert 23 | @GenericGenerator(name = "jpa-uuid", strategy = "uuid") 24 | public class TextBoardPraise { 25 | 26 | @Id 27 | @GeneratedValue(generator = "jpa-uuid") 28 | private String id; 29 | private String userId; 30 | private String textBoardId; 31 | private java.sql.Timestamp createTime; 32 | private java.sql.Timestamp updateTime; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.entity; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonIgnore; 5 | import javax.persistence.Entity; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.Id; 8 | import javax.persistence.Table; 9 | import lombok.AllArgsConstructor; 10 | import lombok.Builder; 11 | import lombok.Data; 12 | import lombok.NoArgsConstructor; 13 | import org.hibernate.annotations.DynamicInsert; 14 | import org.hibernate.annotations.DynamicUpdate; 15 | import org.hibernate.annotations.GenericGenerator; 16 | 17 | @Data 18 | @Entity 19 | @Table(name = "user") 20 | @Builder 21 | @AllArgsConstructor 22 | @NoArgsConstructor 23 | @DynamicUpdate 24 | @DynamicInsert 25 | @GenericGenerator(name = "jpa-uuid", strategy = "uuid") 26 | public class User { 27 | 28 | @Id 29 | @GeneratedValue(generator = "jpa-uuid") 30 | private String id; 31 | private Integer uid; 32 | private String nickName; 33 | private Integer gender; 34 | private String email; 35 | private String headImg; 36 | @JsonIgnore 37 | private String password; 38 | private java.sql.Timestamp createTime; 39 | private java.sql.Timestamp updateTime; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/entity/VerificationCode.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.entity; 2 | 3 | 4 | import javax.persistence.Entity; 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.Id; 7 | import javax.persistence.Table; 8 | import lombok.AllArgsConstructor; 9 | import lombok.Builder; 10 | import lombok.Data; 11 | import lombok.NoArgsConstructor; 12 | import org.hibernate.annotations.DynamicInsert; 13 | import org.hibernate.annotations.DynamicUpdate; 14 | import org.hibernate.annotations.GenericGenerator; 15 | 16 | @Data 17 | @Entity 18 | @Table(name = "verification_code") 19 | @Builder 20 | @AllArgsConstructor 21 | @NoArgsConstructor 22 | @DynamicUpdate 23 | @DynamicInsert 24 | @GenericGenerator(name = "jpa-uuid", strategy = "uuid") 25 | public class VerificationCode { 26 | 27 | @Id 28 | @GeneratedValue(generator = "jpa-uuid") 29 | private String id; 30 | private String email; 31 | private String code; 32 | private java.sql.Timestamp deadline; 33 | private boolean used; 34 | private java.sql.Timestamp createTime; 35 | private java.sql.Timestamp updateTime; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/enums/GameEnum.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.enums; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * @program: devtools-server 7 | * @description: 8 | * @author: wpp 9 | * @create: 2020-08-24 10 | **/ 11 | @Getter 12 | public enum GameEnum { 13 | 14 | //扫雷 15 | SCAN_TNT, 16 | 17 | //拼图 18 | PUZZLE, 19 | 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/enums/TypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.enums; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * @program: devtools-server 7 | * @description: 8 | * @author: wpp 9 | * @create: 2020-08-24 10 | **/ 11 | @Getter 12 | public enum TypeEnum { 13 | 14 | //舔狗 15 | DOG, 16 | 17 | 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/pojo/Result.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.pojo; 2 | 3 | import java.io.Serializable; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | 7 | /** 8 | * @program: volvo 9 | * @description: 统一返回封装 10 | * @author: wpp 11 | * @create: 2020-06-01 12 | **/ 13 | @Data 14 | @Builder 15 | public class Result implements Serializable { 16 | 17 | private static final long serialVersionUID = 3068837394742385883L; 18 | 19 | /** 20 | * 状态码 21 | */ 22 | private Integer code; 23 | 24 | /** 25 | * 提示信息 26 | */ 27 | private String msg; 28 | 29 | /** 30 | * 内容 31 | */ 32 | private T data; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/vo/ResultVo.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.vo; 2 | 3 | import com.wpp.devtools.domain.pojo.Result; 4 | import com.wpp.devtools.enums.ExceptionCodeEnums; 5 | 6 | /** 7 | * @program: language 8 | * @description: 统一返回 9 | * @author: wpp 10 | * @create: 2020-06-01 11 | **/ 12 | public class ResultVo { 13 | 14 | 15 | public static Result success(Object object) { 16 | return Result.builder() 17 | .code(ExceptionCodeEnums.OK.getCode()) 18 | .msg(ExceptionCodeEnums.OK.getMsg()) 19 | .data(object).build(); 20 | } 21 | 22 | public static Result success() { 23 | return success(""); 24 | } 25 | 26 | public static Result error(Integer code, String msg) { 27 | return Result.builder() 28 | .code(code) 29 | .msg(msg) 30 | .build(); 31 | } 32 | 33 | public static Result error() { 34 | return Result.builder() 35 | .code(ExceptionCodeEnums.ERROR.getCode()) 36 | .msg(ExceptionCodeEnums.ERROR.getMsg()) 37 | .build(); 38 | } 39 | 40 | public static Result error(Object object) { 41 | return Result.builder() 42 | .code(ExceptionCodeEnums.ERROR.getCode()) 43 | .msg(ExceptionCodeEnums.ERROR.getMsg()) 44 | .data(object) 45 | .build(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/domain/vo/UserVo.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.domain.vo; 2 | 3 | 4 | import lombok.Data; 5 | 6 | @Data 7 | 8 | public class UserVo { 9 | 10 | private Integer uid; 11 | private String email; 12 | private java.sql.Timestamp createTime; 13 | private String token; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/enums/ExceptionCodeEnums.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.enums; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * @program: volvo 7 | * @description: 异常状态码 8 | * @author: wpp 9 | * @create: 2020-06-01 10 | **/ 11 | @Getter 12 | public enum ExceptionCodeEnums { 13 | 14 | OK(0, "成功"), 15 | ERROR(-1, "失败"), 16 | OTHER_ERROR(-2, "未知异常"), 17 | ID_NULL(-20001, "ID不能为NULL"), 18 | ID_NOT_EXISTS(-20002, "ID不存在"), 19 | JWT_VALID_ERROR(-20003, "身份验证异常"), 20 | JWT_VALID_OVERDUE(-20004, "TOKEN已过期"), 21 | JWT_ERROR(-20005, "TOKEN异常"), 22 | PARAM_ERROR(-20006, "参数异常"), 23 | HTTP_REQUEST_ERROR(-20007, "接口请求异常"), 24 | HTTP_REQUEST_FREQUENTLY(-20008, "请求太频繁"), 25 | GET_IP_ERROR(-20009, "获取IP异常"), 26 | UPLOAD_FILE_NULL(-20010, "上传文件不能为空"), 27 | UPLOAD_FILE_ERROR(-20011, "上传文件异常"), 28 | TEXT_BOARD_PRAISE_EXISTS(-20012, "您已赞"), 29 | PARAM_NULL(-20014, "参数不能为空"), 30 | INSUFFICIENT_AUTHORITY(-20015, "权限不足"), 31 | TIME_ERROR(-20016, "时间解析异常"), 32 | OBJECT_ERROR(-20017, "对象解析异常"), 33 | COMMIT_ERROR(-20018, "请勿重复提交"), 34 | COMPLETE(-20021, "已完成, 无需操作"), 35 | PASSWORD_UNQUALIFIED(-20022, "密码必须包含大小写字母、数字、特殊符号的8位以上组合"), 36 | STREAM_ERROR(-20023, "流异常"), 37 | WX_HTTP_REQUEST_ERROR(-200024, "微信接口请求异常"), 38 | EMAIL_SEND_ERROR(-200025, "邮件发送异常"), 39 | GOD_EMAIL_EXISTS(-200026, "邮箱已存在, 请勿重复添加"), 40 | GOD_EMAIL_CANCEL(-200027, "邮箱已被取消订阅, 无法添加"), 41 | 42 | 43 | ; 44 | 45 | private Integer code; 46 | 47 | private String msg; 48 | 49 | ExceptionCodeEnums(Integer code, String msg) { 50 | this.code = code; 51 | this.msg = msg; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/enums/UserCodeEnums.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.enums; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * @program: volvo 7 | * @description: 异常状态码 8 | * @author: wpp 9 | * @create: 2020-06-01 10 | **/ 11 | @Getter 12 | public enum UserCodeEnums { 13 | 14 | USER_PSW_ERROR(-10001, "账号或密码有误"), 15 | EMAIL_EXIST(-10002, "邮箱已存在"), 16 | EMAIL_NOT_EXIST(-10003, "邮箱不存在"), 17 | DAY_MAX_SEND_EMAIL_SEND_COUNT(-10004, "超出24小时最大发送数量"), 18 | MINUTE_MAX_SEND_EMAIL_SEND_COUNT(-10005, "超出每分钟最大发送数量"), 19 | VERIFICATION_CODE_ERROR(-10006, "验证码错误"), 20 | VERIFICATION_CODE_INVALID(-10007, "验证码过期"), 21 | 22 | ; 23 | 24 | private Integer code; 25 | 26 | private String msg; 27 | 28 | UserCodeEnums(Integer code, String msg) { 29 | this.code = code; 30 | this.msg = msg; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/exception/CustomException.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.exception; 2 | 3 | 4 | import com.wpp.devtools.enums.ExceptionCodeEnums; 5 | import com.wpp.devtools.enums.UserCodeEnums; 6 | import lombok.Data; 7 | 8 | /** 9 | * @program: volvo 10 | * @description: 自定义异常 11 | * @author: wpp 12 | * @create: 2020-06-01 13 | **/ 14 | @Data 15 | public class CustomException extends RuntimeException { 16 | 17 | /** 18 | * 错误状态码. 19 | */ 20 | private Integer code; 21 | 22 | public CustomException(ExceptionCodeEnums exceptionCodeEnums) { 23 | super(exceptionCodeEnums.getMsg()); 24 | this.code = exceptionCodeEnums.getCode(); 25 | } 26 | 27 | public CustomException(ExceptionCodeEnums exceptionCodeEnums, String msg) { 28 | super(msg); 29 | this.code = exceptionCodeEnums.getCode(); 30 | } 31 | 32 | public CustomException(UserCodeEnums userCodeEnums) { 33 | super(userCodeEnums.getMsg()); 34 | this.code = userCodeEnums.getCode(); 35 | } 36 | 37 | public CustomException(UserCodeEnums userCodeEnums, String msg) { 38 | super(msg); 39 | this.code = userCodeEnums.getCode(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/exception/ExceptionAdvice.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.exception; 2 | 3 | 4 | import com.wpp.devtools.domain.pojo.Result; 5 | import com.wpp.devtools.enums.ExceptionCodeEnums; 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | import javax.validation.ConstraintViolation; 9 | import javax.validation.ConstraintViolationException; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.apache.commons.lang3.StringUtils; 12 | import org.springframework.validation.BindException; 13 | import org.springframework.validation.BindingResult; 14 | import org.springframework.validation.FieldError; 15 | import org.springframework.web.bind.MethodArgumentNotValidException; 16 | import org.springframework.web.bind.MissingServletRequestParameterException; 17 | import org.springframework.web.bind.annotation.ControllerAdvice; 18 | import org.springframework.web.bind.annotation.ExceptionHandler; 19 | import org.springframework.web.bind.annotation.ResponseBody; 20 | 21 | /** 22 | * @program: volvo 23 | * @description: 统一异常处理 24 | * @author: wpp 25 | * @create: 2020-06-01 26 | **/ 27 | @Slf4j 28 | @ControllerAdvice 29 | public class ExceptionAdvice { 30 | 31 | 32 | /** 33 | * 全局异常捕捉 34 | * 35 | * @return 36 | */ 37 | @ResponseBody 38 | @ExceptionHandler(value = Exception.class) 39 | public Result errorHandler(Exception e) { 40 | log.error(e.getMessage()); 41 | e.printStackTrace(); 42 | return Result.builder() 43 | .code(ExceptionCodeEnums.ERROR.getCode()) 44 | .msg(ExceptionCodeEnums.ERROR.getMsg()) 45 | .data("") 46 | .build(); 47 | } 48 | 49 | 50 | /** 51 | * 自定义异常捕获 52 | * 53 | * @param e 54 | * @return 55 | */ 56 | @ResponseBody 57 | @ExceptionHandler(value = CustomException.class) 58 | public Result customException(CustomException e) { 59 | log.info(e.getMessage()); 60 | return Result.builder() 61 | .code(e.getCode()) 62 | .msg(e.getMessage()) 63 | .data("") 64 | .build(); 65 | } 66 | 67 | 68 | /** 69 | * 入参校验异常捕获 70 | * 71 | * @param e 72 | * @return 73 | */ 74 | @ResponseBody 75 | @ExceptionHandler(value = MissingServletRequestParameterException.class) 76 | public Result customException(MissingServletRequestParameterException e) { 77 | return Result.builder() 78 | .code(ExceptionCodeEnums.PARAM_ERROR.getCode()) 79 | .msg(e.getParameterName() + "不能为空") 80 | .data("") 81 | .build(); 82 | } 83 | 84 | /** 85 | * valid入参异常处理 86 | * 87 | * @param e 88 | * @return 89 | */ 90 | @ResponseBody 91 | @ExceptionHandler(value = MethodArgumentNotValidException.class) 92 | public Result customException(MethodArgumentNotValidException e) { 93 | return customResult(e.getBindingResult()); 94 | 95 | } 96 | 97 | 98 | /** 99 | * valid入参异常处理 100 | * 101 | * @param e 102 | * @return 103 | */ 104 | @ResponseBody 105 | @ExceptionHandler(value = BindException.class) 106 | public Result customException(BindException e) { 107 | return customResult(e.getBindingResult()); 108 | } 109 | 110 | 111 | /** 112 | * List valid入参异常处理 113 | * 114 | * @param e 115 | * @return 116 | */ 117 | @ResponseBody 118 | @ExceptionHandler(value = ConstraintViolationException.class) 119 | public Result customException(ConstraintViolationException e) { 120 | Set> violations = e.getConstraintViolations(); 121 | Set set = new HashSet<>(); 122 | for (ConstraintViolation violation : violations) { 123 | set.add(violation.getMessage()); 124 | } 125 | return Result.builder() 126 | .code(ExceptionCodeEnums.PARAM_ERROR.getCode()) 127 | .msg(StringUtils.join(set, ",")) 128 | .data("") 129 | .build(); 130 | } 131 | 132 | /** 133 | * 验证参数统一返回 134 | * 135 | * @param bindingResult 136 | * @return 137 | */ 138 | public Result customResult(BindingResult bindingResult) { 139 | Set set = new HashSet<>(); 140 | for (FieldError fieldError : bindingResult.getFieldErrors()) { 141 | set.add(fieldError.getDefaultMessage()); 142 | } 143 | return Result.builder() 144 | .code(ExceptionCodeEnums.PARAM_ERROR.getCode()) 145 | .msg(StringUtils.join(set, ",")) 146 | .data("") 147 | .build(); 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/model/Cros.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.model; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.cors.CorsConfiguration; 6 | import org.springframework.web.cors.UrlBasedCorsConfigurationSource; 7 | import org.springframework.web.filter.CorsFilter; 8 | 9 | /** 10 | * @program: volvo 11 | * @description: 跨域设置 12 | * @author: wpp 13 | * @create: 2020-06-03 14 | **/ 15 | 16 | @Configuration 17 | public class Cros { 18 | 19 | private CorsConfiguration buildConfig() { 20 | CorsConfiguration corsConfiguration = new CorsConfiguration(); 21 | corsConfiguration.addAllowedOrigin("*"); // 允许任何域名使用 22 | corsConfiguration.addAllowedHeader("*"); // 允许任何头 23 | corsConfiguration.addAllowedMethod("*"); // 允许任何方法(post、get等) 24 | return corsConfiguration; 25 | } 26 | 27 | @Bean 28 | public CorsFilter corsFilter() { 29 | UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); 30 | source.registerCorsConfiguration("/**", buildConfig()); // 对接口配置跨域设置 31 | return new CorsFilter(source); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/model/FilterInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.model; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.wpp.devtools.config.JWTConfig; 5 | import com.wpp.devtools.config.RedisKeyConfig; 6 | import com.wpp.devtools.domain.annotation.AccessLimit; 7 | import com.wpp.devtools.enums.ExceptionCodeEnums; 8 | import com.wpp.devtools.exception.CustomException; 9 | import com.wpp.devtools.util.CommonUtils; 10 | import com.wpp.devtools.util.JWTUtil; 11 | import com.wpp.devtools.util.RedistUtil; 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | 15 | import io.netty.util.internal.StringUtil; 16 | import lombok.extern.slf4j.Slf4j; 17 | import org.apache.commons.lang3.StringUtils; 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.stereotype.Component; 20 | import org.springframework.web.method.HandlerMethod; 21 | import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; 22 | 23 | /** 24 | * @program: devtools-server 25 | * @description: 26 | * @author: wpp 27 | * @create: 2020-07-06 28 | **/ 29 | @Component 30 | @Slf4j 31 | public class FilterInterceptor extends HandlerInterceptorAdapter { 32 | 33 | 34 | @Autowired 35 | private JWTUtil jwtUtil; 36 | 37 | @Autowired 38 | private RedistUtil redistUtil; 39 | 40 | @Override 41 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 42 | Object handler) { 43 | 44 | String ip = CommonUtils.getIpAddr(request); 45 | log.info("IP进入: " + ip); 46 | //IP黑名单 47 | if (redistUtil.getStringToHash(RedisKeyConfig.BLACKLIST, ip)) { 48 | throw new CustomException(ExceptionCodeEnums.HTTP_REQUEST_FREQUENTLY); 49 | } 50 | 51 | //判断请求是否属于方法的请求 52 | if (handler instanceof HandlerMethod) { 53 | 54 | HandlerMethod hm = (HandlerMethod) handler; 55 | 56 | //获取方法中的注解,看是否有该注解 57 | AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class); 58 | if (accessLimit == null) { 59 | return true; 60 | } 61 | int seconds = accessLimit.seconds(); 62 | int maxCount = accessLimit.maxCount(); 63 | String uri = request.getRequestURI(); 64 | String key = uri + ip; 65 | 66 | String countString = redistUtil.getString(key); 67 | if (countString == null) { 68 | //第一次访问 69 | redistUtil.incr(key, Long.valueOf(seconds)); 70 | } else if (Integer.valueOf(countString) < maxCount) { 71 | //加1 72 | redistUtil.incr(key); 73 | } else { 74 | //超出访问次数 75 | log.info("ip: " + ip + ", 请求太频繁"); 76 | redistUtil.delKey(key); 77 | Long warningCount = redistUtil.incr(RedisKeyConfig.WARNING + ip, 3600 * 24); 78 | //警告次数超过10次,ip上黑名单 79 | if (warningCount > 10) { 80 | redistUtil.setStringToHash(RedisKeyConfig.BLACKLIST, ip, ""); 81 | } 82 | throw new CustomException(ExceptionCodeEnums.HTTP_REQUEST_FREQUENTLY); 83 | } 84 | } 85 | 86 | final String authHeader = request.getHeader(JWTConfig.JWT_HEADER); 87 | if(StringUtils.isNotBlank(authHeader)) { 88 | final JSONObject jsonObject = jwtUtil.parseJWT(authHeader); 89 | request.setAttribute(JWTConfig.JWT_USER_ID_KEY, jsonObject.get(JWTConfig.JWT_USER_ID_KEY)); 90 | } 91 | 92 | 93 | return true; 94 | } 95 | 96 | 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/model/JWTInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.model; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.wpp.devtools.config.JWTConfig; 5 | import com.wpp.devtools.enums.ExceptionCodeEnums; 6 | import com.wpp.devtools.exception.CustomException; 7 | import com.wpp.devtools.util.JWTUtil; 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Component; 13 | import org.springframework.web.servlet.HandlerInterceptor; 14 | 15 | /** 16 | * @program: devtools-server 17 | * @description: 18 | * @author: wpp 19 | * @create: 2020-07-06 20 | **/ 21 | @Component 22 | @Slf4j 23 | public class JWTInterceptor implements HandlerInterceptor { 24 | 25 | @Override 26 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 27 | Object handler) { 28 | final String authHeader = request.getHeader(JWTConfig.JWT_HEADER); 29 | if ("OPTIONS".equals(request.getMethod())) { 30 | response.setStatus(HttpServletResponse.SC_OK); 31 | return true; 32 | } else { 33 | if (null == authHeader || !authHeader.startsWith(JWTConfig.JWT_BEARER)) { 34 | throw new CustomException(ExceptionCodeEnums.JWT_VALID_ERROR); 35 | } 36 | } 37 | return true; 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/model/Schedule.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.model; 2 | 3 | import com.wpp.devtools.service.UserService; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.ScheduledExecutorService; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.scheduling.annotation.EnableScheduling; 10 | import org.springframework.scheduling.annotation.Scheduled; 11 | import org.springframework.scheduling.annotation.SchedulingConfigurer; 12 | import org.springframework.scheduling.config.ScheduledTaskRegistrar; 13 | 14 | /** 15 | * @program: devtools-server 16 | * @description: 定时任务 17 | * @author: wpp 18 | * @create: 2020-07-09 19 | **/ 20 | @Configuration 21 | @EnableScheduling 22 | @Slf4j 23 | public class Schedule implements SchedulingConfigurer { 24 | 25 | @Override 26 | public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { 27 | ScheduledExecutorService taskExecutor = Executors.newScheduledThreadPool(3); 28 | scheduledTaskRegistrar.setScheduler(taskExecutor); 29 | } 30 | 31 | @Autowired 32 | private UserService userService; 33 | 34 | //每小时执行一次 35 | //发送订阅任务 36 | @Scheduled(cron = "0 0 * * * ?") 37 | public void task1() { 38 | long startTime = System.currentTimeMillis(); 39 | int count = userService.sendSubscribe(); 40 | log.info("定时任务: {}, 完成, 耗时: {}s, 发送量: {}", "发送订阅", 41 | (System.currentTimeMillis() - startTime) / 1000, count); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/model/Swagger.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import springfox.documentation.builders.ApiInfoBuilder; 8 | import springfox.documentation.builders.PathSelectors; 9 | import springfox.documentation.builders.RequestHandlerSelectors; 10 | import springfox.documentation.service.ApiInfo; 11 | import springfox.documentation.service.ApiKey; 12 | import springfox.documentation.service.AuthorizationScope; 13 | import springfox.documentation.service.SecurityReference; 14 | import springfox.documentation.service.SecurityScheme; 15 | import springfox.documentation.spi.DocumentationType; 16 | import springfox.documentation.spi.service.contexts.SecurityContext; 17 | import springfox.documentation.spring.web.plugins.Docket; 18 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 19 | 20 | /** 21 | * @program: volvo 22 | * @description: swagger 23 | * @author: wpp 24 | * @create: 2020-06-01 25 | **/ 26 | @Configuration 27 | @EnableSwagger2 28 | public class Swagger { 29 | 30 | 31 | @Bean 32 | public Docket createRestApi() { 33 | Docket docket = new Docket(DocumentationType.SWAGGER_2) 34 | .apiInfo(apiInfo()) 35 | .select() 36 | .apis(RequestHandlerSelectors 37 | .basePackage("com.wpp.devtools.controller")) 38 | .paths(PathSelectors.any()) 39 | .build() 40 | .securitySchemes(securitySchemes()) 41 | .securityContexts(securityContexts()); 42 | return docket; 43 | } 44 | 45 | private ApiInfo apiInfo() { 46 | return new ApiInfoBuilder() 47 | .title("SpringBoot整合Swagger") 48 | .description("SpringBoot整合Swagger,详细信息......") 49 | .version("2.0") 50 | .build(); 51 | } 52 | 53 | /** 54 | * SecurityScheme 子类 BasicAuth OAuth ApiKey 55 | * 56 | * @return 57 | */ 58 | private List securitySchemes() { 59 | List list = new ArrayList<>(); 60 | list.add(new ApiKey("Authorization", "Authorization", "header")); 61 | return list; 62 | } 63 | 64 | 65 | private List securityContexts() { 66 | List securityContexts = new ArrayList<>(); 67 | securityContexts.add(SecurityContext.builder() 68 | .securityReferences(defaultAuth()) 69 | .forPaths(PathSelectors.regex("^(?!auth).*$")).build()); 70 | return securityContexts; 71 | } 72 | 73 | private List defaultAuth() { 74 | AuthorizationScope authorizationScope = new AuthorizationScope("global", 75 | "accessEverything"); 76 | AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; 77 | authorizationScopes[0] = authorizationScope; 78 | List securityReferences = new ArrayList<>(); 79 | securityReferences.add(new SecurityReference("Authorization", authorizationScopes)); 80 | return securityReferences; 81 | 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/model/WebConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.model; 2 | 3 | 4 | import java.util.Arrays; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 8 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 9 | 10 | /** 11 | * @program: devtools-server 12 | * @description: 13 | * @author: wpp 14 | * @create: 2020-07-06 15 | **/ 16 | 17 | @Configuration 18 | public class WebConfiguration implements WebMvcConfigurer { 19 | 20 | //spring拦截器加载在springcontentText之前,所以这里用@Bean提前加载。否则会导致过滤器中的@AutoWired注入为空 21 | 22 | @Bean 23 | FilterInterceptor filternterceptor() { 24 | return new FilterInterceptor(); 25 | } 26 | 27 | @Bean 28 | JWTInterceptor jwtInterceptor() { 29 | return new JWTInterceptor(); 30 | } 31 | 32 | 33 | @Override 34 | public void addInterceptors(InterceptorRegistry registry) { 35 | registry.addInterceptor(filternterceptor()) 36 | .addPathPatterns("/**") 37 | .excludePathPatterns("/favicon.ico") 38 | .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", 39 | "/swagger-ui.html/**"); 40 | 41 | registry.addInterceptor(jwtInterceptor()) 42 | .addPathPatterns("/user/**") 43 | .excludePathPatterns("/favicon.ico") 44 | .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", 45 | "/swagger-ui.html/**"); 46 | // .excludePathPatterns(Arrays.asList("/unAuth/**", "/devTools/**")); 47 | 48 | 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/repository/ActivityRepository.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.repository; 2 | 3 | import com.wpp.devtools.domain.entity.Activity; 4 | import java.util.List; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | /** 9 | * @program: devtools-server 10 | * @description: 11 | * @author: wpp 12 | * @create: 2020-09-17 13 | **/ 14 | @Repository 15 | public interface ActivityRepository extends JpaRepository { 16 | 17 | List findAllByOrderBySort(); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/repository/DogTextRepository.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.repository; 2 | 3 | import com.wpp.devtools.domain.entity.DogText; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Query; 6 | import org.springframework.stereotype.Repository; 7 | 8 | /** 9 | * @program: devtools-server 10 | * @description: 11 | * @author: wpp 12 | * @create: 2020-08-13 13 | **/ 14 | @Repository 15 | public interface DogTextRepository extends JpaRepository { 16 | 17 | DogText findByContent(String content); 18 | 19 | @Query(value = "SELECT content FROM dog_text ORDER BY RAND() LIMIT 1", nativeQuery = true) 20 | String findContentByRandom(); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/repository/EveryDayTextRepository.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.repository; 2 | 3 | import com.wpp.devtools.domain.entity.EveryDayText; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Query; 6 | import org.springframework.stereotype.Repository; 7 | 8 | /** 9 | * @program: devtools-server 10 | * @description: 11 | * @author: wpp 12 | * @create: 2020-08-21 13 | **/ 14 | @Repository 15 | public interface EveryDayTextRepository extends JpaRepository { 16 | 17 | EveryDayText findByTitle(String title); 18 | 19 | @Query(value = "SELECT * FROM every_day_text ORDER BY RAND() LIMIT 1", nativeQuery = true) 20 | EveryDayText findOneTextByRandom(); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/repository/GameRecordRepository.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.repository; 2 | 3 | import com.wpp.devtools.domain.entity.GameRecord; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Query; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | * @program: devtools-server 13 | * @description: 14 | * @author: wpp 15 | * @create: 2020-09-17 16 | **/ 17 | @Repository 18 | public interface GameRecordRepository extends JpaRepository { 19 | 20 | GameRecord findByUserId(String userId); 21 | 22 | @Query(value = "SELECT a.game_level gameLevel, a.seconds, b.nick_name nickName, b.head_img headImg " + 23 | "FROM `game_record` a " + 24 | "LEFT JOIN user b ON b.id = a.user_id " + 25 | "WHERE a.game_code = ?1 AND a.seconds IS NOT NULL ORDER BY a.seconds ASC limit 1000", nativeQuery = true) 26 | List> findGameRank(String gameCode); 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/repository/NotebookRepository.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.repository; 2 | 3 | import com.wpp.devtools.domain.entity.Notebook; 4 | import java.util.List; 5 | import javax.transaction.Transactional; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | import org.springframework.data.jpa.repository.Modifying; 8 | import org.springframework.data.jpa.repository.Query; 9 | import org.springframework.stereotype.Repository; 10 | 11 | /** 12 | * @program: devtools-server 13 | * @description: 14 | * @author: wpp 15 | * @create: 2021-01-14 16 | **/ 17 | @Repository 18 | public interface NotebookRepository extends JpaRepository { 19 | 20 | 21 | List findAllByUserIdOrderBySortAsc(String userId); 22 | 23 | @Transactional 24 | @Modifying 25 | @Query(value = "update notebook set sort = sort + ?2 where user_id = ?1 and sort >= ?4 and sort < ?3 ", nativeQuery = true) 26 | void updateSortAllTopById(String userId, long deviation, long oldIndex, long newIndex); 27 | 28 | @Transactional 29 | @Modifying 30 | @Query(value = "update notebook set sort = sort + ?2 where user_id = ?1 and sort > ?3 and sort <= ?4 ", nativeQuery = true) 31 | void updateSortAllDownById(String userId, long deviation, long oldIndex, long newIndex); 32 | 33 | @Transactional 34 | @Modifying 35 | @Query(value = "update notebook set sort = ?3 where id = ?1 and sort = ?2 ", nativeQuery = true) 36 | void updateSortById(String id, long oldIndex, long newIndex); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/repository/SubscribeRecordRepository.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.repository; 2 | 3 | import com.wpp.devtools.domain.entity.SubscribeRecord; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | /** 8 | * @program: devtools-server 9 | * @description: 10 | * @author: wpp 11 | * @create: 2020-09-21 12 | **/ 13 | @Repository 14 | public interface SubscribeRecordRepository extends JpaRepository { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/repository/SubscribeRepository.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.repository; 2 | 3 | import com.wpp.devtools.domain.entity.Subscribe; 4 | import java.util.List; 5 | import java.util.Map; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | import org.springframework.data.jpa.repository.Query; 8 | import org.springframework.stereotype.Repository; 9 | 10 | /** 11 | * @program: devtools-server 12 | * @description: 13 | * @author: wpp 14 | * @create: 2020-09-17 15 | **/ 16 | @Repository 17 | public interface SubscribeRepository extends JpaRepository { 18 | 19 | @Query(value = "SELECT a.* FROM `subscribe` a " 20 | + "LEFT JOIN `subscribe_record` b ON b.`subscribe_id` = a.`id` AND TO_DAYS(b.`create_time`) = TO_DAYS(NOW()) " 21 | + "WHERE a.hour = ?1 " 22 | + "AND a.email IS NOT NULL " 23 | + "AND b.id IS NULL " 24 | + "AND a.`enabled` = 1 " 25 | + "AND a.cancel = 0 ", nativeQuery = true) 26 | List findAllSubscribe(int hour); 27 | 28 | @Query(value = "SELECT * FROM `subscribe` WHERE email = ?1 ", nativeQuery = true) 29 | Subscribe findCancelByEmail(String email); 30 | 31 | @Query(value = "SELECT a.*, COUNT(b.id) `count` FROM `subscribe` a " 32 | + "LEFT JOIN `subscribe_record` b ON b.`subscribe_id` = a.`id` " 33 | + "WHERE a.user_id = ?1 " 34 | + "GROUP BY a.id " 35 | + "ORDER BY a.create_time ASC ", nativeQuery = true) 36 | List> findList(String userId); 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/repository/TextBoardPraiseRepository.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.repository; 2 | 3 | import com.wpp.devtools.domain.entity.TextBoardPraise; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Query; 6 | import org.springframework.stereotype.Repository; 7 | 8 | /** 9 | * @program: devtools-server 10 | * @description: 11 | * @author: wpp 12 | * @create: 2020-08-18 13 | **/ 14 | @Repository 15 | public interface TextBoardPraiseRepository extends JpaRepository { 16 | 17 | 18 | @Query(value="SELECT COUNT(*) FROM `text_board_praise` WHERE user_id = ?1 AND text_board_id = ?2", nativeQuery = true) 19 | int findParaiseRecordCount(String userId, String msgId); 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/repository/TextBoardRepository.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.repository; 2 | 3 | import com.wpp.devtools.domain.entity.TextBoard; 4 | import java.util.List; 5 | import java.util.Map; 6 | import javax.transaction.Transactional; 7 | import org.springframework.data.jpa.repository.JpaRepository; 8 | import org.springframework.data.jpa.repository.Modifying; 9 | import org.springframework.data.jpa.repository.Query; 10 | import org.springframework.stereotype.Repository; 11 | 12 | /** 13 | * @program: devtools-server 14 | * @description: 15 | * @author: wpp 16 | * @create: 2020-08-18 17 | **/ 18 | @Repository 19 | public interface TextBoardRepository extends JpaRepository { 20 | 21 | 22 | @Query(value="SELECT a.id, a.content, a.praise_count, a.create_time, CASE WHEN b.id IS NULL THEN FALSE ELSE TRUE END AS praise, c.head_img " + 23 | "FROM text_board a " + 24 | "LEFT JOIN text_board_praise b ON b.text_board_id = a.id AND b.user_id = ?3 " + 25 | "LEFT JOIN user c ON c.id = a.user_id " + 26 | "WHERE a.parent_id = 0 " + 27 | "ORDER BY a.create_time DESC LIMIT ?1, ?2 ", nativeQuery = true) 28 | List> findAllByPage(int pageNo, int pageSize, String userId); 29 | 30 | @Query(value="SELECT a.id, a.content, a.parent_id parentId, a.praise_count praiseCount, a.create_time createTime, CASE WHEN b.id IS NULL THEN FALSE ELSE TRUE END AS praise, c.head_img " + 31 | "FROM text_board a " + 32 | "LEFT JOIN text_board_praise b ON b.text_board_id = a.id AND b.user_id = ?2 " + 33 | "LEFT JOIN user c ON c.id = a.user_id " + 34 | "WHERE a.parent_id IN ?1 " + 35 | "ORDER BY a.create_time DESC ", nativeQuery = true) 36 | List> findAllByParentIds(List parentIds, String userId); 37 | 38 | @Transactional 39 | @Modifying 40 | @Query(value = "UPDATE `text_board` SET praise_count = praise_count + 1 WHERE id = ?1", nativeQuery = true) 41 | void addPraiseCount(String id); 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.repository; 2 | 3 | import com.wpp.devtools.domain.entity.User; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | /** 8 | * @program: devtools-server 9 | * @description: 10 | * @author: wpp 11 | * @create: 2020-08-17 12 | **/ 13 | @Repository 14 | public interface UserRepository extends JpaRepository { 15 | 16 | User findByEmailAndPassword(String email, String paasword); 17 | 18 | User findByEmail(String email); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/repository/VerificationCodeRepository.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.repository; 2 | 3 | import com.wpp.devtools.domain.entity.VerificationCode; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | /** 8 | * @program: devtools-server 9 | * @description: 10 | * @author: wpp 11 | * @create: 2020-09-17 12 | **/ 13 | @Repository 14 | public interface VerificationCodeRepository extends JpaRepository { 15 | 16 | VerificationCode findByEmailAndCodeAndUsed(String email, String code, Boolean used); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/service/DevtoolsService.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.service; 2 | 3 | import com.wpp.devtools.util.CommonUtils; 4 | import java.awt.Color; 5 | import java.awt.image.BufferedImage; 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.IOException; 8 | import java.util.Arrays; 9 | import javax.imageio.ImageIO; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.web.multipart.MultipartFile; 12 | 13 | @Service 14 | public class DevtoolsService { 15 | 16 | /** 17 | * 图片转base64 18 | * 19 | * @param file 20 | * @return 21 | */ 22 | public Object imgToBase64(MultipartFile file) { 23 | String originalFilename = file.getOriginalFilename(); 24 | String type = originalFilename.substring(originalFilename.lastIndexOf(".") + 1); 25 | return "data:image/" + type + ";base64," + CommonUtils.toBaseImg64(file); 26 | } 27 | 28 | /** 29 | * 图片加水印 30 | * 31 | * @param file 32 | * @return 33 | */ 34 | public Object imgAddWatermark(MultipartFile file) { 35 | 36 | return null; 37 | 38 | } 39 | 40 | 41 | /** 42 | * 图片去水印 43 | * 44 | * @param file 45 | * @param backgroundColor 46 | * @param backgroundColor 47 | * @return 48 | */ 49 | public Object imgClearWatermark(MultipartFile file, String backgroundColor, String watermarkColor, int precision) { 50 | BufferedImage bi = null; 51 | try { 52 | bi = ImageIO.read(file.getInputStream()); 53 | } catch (IOException e) { 54 | e.printStackTrace(); 55 | } 56 | //背景值 57 | int[] bgC = Arrays.asList(backgroundColor.replace(" ", "").split(",")).stream().mapToInt(Integer::parseInt).toArray(); 58 | int[] wmC = Arrays.asList(watermarkColor.replace(" ", "").split(",")).stream().mapToInt(Integer::parseInt).toArray(); 59 | 60 | Color wColor = new Color(bgC[0], bgC[1], bgC[2]); 61 | for (int i = 0; i < bi.getWidth(); i++) { 62 | for (int j = 0; j < bi.getHeight(); j++) { 63 | int color = bi.getRGB(i, j); 64 | Color oriColor = new Color(color); 65 | int red = oriColor.getRed(); 66 | int greed = oriColor.getGreen(); 67 | int blue = oriColor.getBlue(); 68 | //替换颜色 69 | if ((red > wmC[0] - precision && red < wmC[0] + precision) && 70 | (greed > wmC[1] - precision && greed < wmC[1] + precision) && 71 | (blue > wmC[2] - precision && blue < wmC[2] + precision)) { 72 | bi.setRGB(i, j, wColor.getRGB()); 73 | } 74 | } 75 | } 76 | String originalFilename = file.getOriginalFilename(); 77 | String type = originalFilename.substring(originalFilename.lastIndexOf(".") + 1); 78 | 79 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 80 | try { 81 | ImageIO.write(bi, type, stream); 82 | } catch (IOException e) { 83 | e.printStackTrace(); 84 | } 85 | // byte[] base64 = Base64.encode(stream.toByteArray()); 86 | try { 87 | stream.close(); 88 | stream.flush(); 89 | bi.flush(); 90 | } catch (IOException e) { 91 | e.printStackTrace(); 92 | } 93 | return null; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/service/GameService.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.service; 2 | 3 | import com.wpp.devtools.domain.bo.PlayGameBo; 4 | import com.wpp.devtools.domain.entity.GameRecord; 5 | import com.wpp.devtools.repository.GameRecordRepository; 6 | import org.apache.commons.lang3.StringUtils; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.util.ObjectUtils; 10 | 11 | import java.sql.Timestamp; 12 | import java.util.Date; 13 | import java.util.List; 14 | import java.util.Map; 15 | import java.util.UUID; 16 | import java.util.stream.Collectors; 17 | 18 | @Service 19 | public class GameService { 20 | 21 | @Autowired 22 | private GameRecordRepository gameRecordRepository; 23 | 24 | /** 25 | * 游戏开始接口 26 | * @param playGameBo 27 | * @param userId 28 | * @return 29 | */ 30 | public void playGame(PlayGameBo playGameBo, String userId) { 31 | if(StringUtils.isBlank(userId)) { 32 | return; 33 | } 34 | 35 | GameRecord gameRecord = GameRecord.builder() 36 | .userId(userId) 37 | .gameCode(playGameBo.getGameCode()) 38 | .gameLevel(playGameBo.getGameLevel()) 39 | .startTime(new Timestamp(new Date().getTime())) 40 | .build(); 41 | gameRecordRepository.save(gameRecord); 42 | } 43 | 44 | 45 | /** 46 | * 游戏结束接口 47 | * @param userId 48 | * @return 49 | */ 50 | public void gameEnd(String userId) { 51 | if(StringUtils.isBlank(userId)) { 52 | return; 53 | } 54 | 55 | GameRecord gameRecord = gameRecordRepository.findByUserId(userId); 56 | if(ObjectUtils.isEmpty(gameRecord)) { 57 | return; 58 | } 59 | 60 | Timestamp endTimestamp = new Timestamp(new Date().getTime()); 61 | //计算耗时多少秒 62 | Long seconds = (endTimestamp.getTime() - gameRecord.getStartTime().getTime()) / 1000; 63 | gameRecord.setEndTime(endTimestamp); 64 | gameRecord.setSeconds(seconds); 65 | gameRecordRepository.save(gameRecord); 66 | } 67 | 68 | 69 | /** 70 | * 游戏排行榜查询 71 | * @param gameCode 72 | * @return 73 | */ 74 | public Map>> gameRank(String gameCode) { 75 | List> rankList = gameRecordRepository.findGameRank(gameCode); 76 | Map>> mapRank = rankList.stream().collect(Collectors.groupingBy(e -> e.get("gameLevel").toString())); 77 | return mapRank; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/service/UnAuthService.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.service; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.wpp.devtools.config.BaiduConfig; 6 | import com.wpp.devtools.config.CommonConfig; 7 | import com.wpp.devtools.config.RedisKeyConfig; 8 | import com.wpp.devtools.config.UrlConfig; 9 | import com.wpp.devtools.domain.bo.ForgetPasswordBo; 10 | import com.wpp.devtools.domain.bo.LoginBo; 11 | import com.wpp.devtools.domain.bo.RegisterBo; 12 | import com.wpp.devtools.domain.entity.*; 13 | import com.wpp.devtools.domain.enums.TypeEnum; 14 | import com.wpp.devtools.domain.vo.UserVo; 15 | import com.wpp.devtools.enums.ExceptionCodeEnums; 16 | import com.wpp.devtools.enums.UserCodeEnums; 17 | import com.wpp.devtools.exception.CustomException; 18 | import com.wpp.devtools.repository.DogTextRepository; 19 | import com.wpp.devtools.repository.EveryDayTextRepository; 20 | import com.wpp.devtools.repository.TextBoardPraiseRepository; 21 | import com.wpp.devtools.repository.TextBoardRepository; 22 | import com.wpp.devtools.repository.UserRepository; 23 | import com.wpp.devtools.repository.VerificationCodeRepository; 24 | import com.wpp.devtools.util.CommonUtils; 25 | import com.wpp.devtools.util.EmailUtil; 26 | import com.wpp.devtools.util.HttpUtil; 27 | import com.wpp.devtools.util.JWTUtil; 28 | import com.wpp.devtools.util.MD5Util; 29 | import com.wpp.devtools.util.RedistUtil; 30 | 31 | import java.io.BufferedReader; 32 | import java.io.InputStreamReader; 33 | import java.net.HttpURLConnection; 34 | import java.net.URL; 35 | import java.sql.Timestamp; 36 | import java.text.MessageFormat; 37 | import java.util.Date; 38 | import java.util.List; 39 | import java.util.Map; 40 | import java.util.stream.Collectors; 41 | import javax.servlet.http.HttpServletRequest; 42 | 43 | import org.jsoup.Jsoup; 44 | import org.jsoup.nodes.Document; 45 | import org.jsoup.nodes.Element; 46 | import org.jsoup.select.Elements; 47 | import org.springframework.beans.factory.annotation.Autowired; 48 | import org.springframework.beans.factory.annotation.Value; 49 | import org.springframework.http.HttpMethod; 50 | import org.springframework.http.MediaType; 51 | import org.springframework.stereotype.Service; 52 | import org.springframework.transaction.annotation.Transactional; 53 | import org.springframework.util.LinkedMultiValueMap; 54 | import org.springframework.util.MultiValueMap; 55 | import org.springframework.util.StringUtils; 56 | import org.springframework.web.multipart.MultipartFile; 57 | 58 | @Service 59 | public class UnAuthService { 60 | 61 | @Autowired 62 | private BaiduConfig baiduConfig; 63 | 64 | @Autowired 65 | private RedistUtil redistUtil; 66 | 67 | @Autowired 68 | private DogTextRepository dogTextRepository; 69 | 70 | @Autowired 71 | private TextBoardRepository textBoardRepository; 72 | 73 | @Autowired 74 | private EveryDayTextRepository everyDayTextRepository; 75 | 76 | @Autowired 77 | private TextBoardPraiseRepository textBoardPraiseRepository; 78 | 79 | @Autowired 80 | private VerificationCodeRepository verificationCodeRepository; 81 | 82 | @Autowired 83 | private EmailUtil emailUtil; 84 | 85 | @Autowired 86 | private UserRepository userRepository; 87 | 88 | @Autowired 89 | private JWTUtil jwtUtil; 90 | 91 | @Value("${HEFENG.KEY}") 92 | private String hefengKey; 93 | 94 | /** 95 | * 舔狗日记 96 | * 97 | * @return 98 | */ 99 | public String getDoglickingDiary() { 100 | return dogTextRepository.findContentByRandom(); 101 | 102 | } 103 | 104 | /** 105 | * 每日一文添加 106 | */ 107 | public void addEveryDayText() { 108 | 109 | for (int i = 0; i < 10000; i++) { 110 | String result; 111 | try { 112 | URL url = new URL("https://meiriyiwen.com/"); 113 | System.out.println(url); 114 | HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 115 | 116 | conn.setRequestMethod("GET"); 117 | conn.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1096.1 Safari/536.6"); 118 | conn.setRequestProperty("content-type","text/html;charset=UTF-8"); 119 | conn.setDoOutput(true); 120 | 121 | 122 | BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); 123 | StringBuffer sb = new StringBuffer(); 124 | String s = ""; 125 | while ((s = rd.readLine()) != null) { 126 | sb.append(s); 127 | } 128 | if (sb.length() == 0) { 129 | sb.append("[]"); 130 | } 131 | result = sb.toString(); 132 | System.out.println(result); 133 | Document document = Jsoup.parse(result); 134 | //Elements head = document.getElementsByTag("head"); 135 | Element element = document.getElementById("article_show"); 136 | String title = element.getElementsByTag("h1").html(); 137 | String author = element.getElementsByTag("span").html().replace("\n", ""); 138 | String content = element.getElementsByClass("article_text").html(); 139 | 140 | EveryDayText everyDayText = everyDayTextRepository.findByTitle(title); 141 | if(null == everyDayText) { 142 | EveryDayText e = EveryDayText.builder() 143 | .title(title) 144 | .author(author) 145 | .content(content) 146 | .build(); 147 | everyDayTextRepository.save(e); 148 | } 149 | rd.close(); 150 | conn.disconnect(); 151 | } catch (Exception e) { 152 | e.printStackTrace(); 153 | } 154 | } 155 | } 156 | /** 157 | * 每日一文 158 | * 159 | * @return 160 | */ 161 | public EveryDayText getEveryDayText() { 162 | return everyDayTextRepository.findOneTextByRandom(); 163 | } 164 | 165 | /** 166 | * 同步舔狗日记 167 | * 168 | * @throws InterruptedException 169 | */ 170 | public void getDoglickingDiaryListInsert() throws InterruptedException { 171 | MultiValueMap headers = new LinkedMultiValueMap<>(); 172 | headers.add("token", CommonConfig.ALAPI_TOKEN); 173 | headers.add("format", "json"); 174 | MultiValueMap param = new LinkedMultiValueMap<>(); 175 | 176 | for (int i = 0; i < 5000; i++) { 177 | try { 178 | String result = HttpUtil 179 | .get("https://v2.alapi.cn/api/dog", param, headers); 180 | JSONObject js = JSONObject.parseObject(result); 181 | String content = JSONObject.parseObject(js.getString("data")).getString("content"); 182 | 183 | DogText e = dogTextRepository.findByContent(content); 184 | if (null == e) { 185 | DogText d = DogText.builder() 186 | .content(content) 187 | .build(); 188 | dogTextRepository.save(d); 189 | } 190 | Thread.sleep(1000); 191 | } catch (Exception e) { 192 | Thread.sleep(10000); 193 | } 194 | } 195 | } 196 | 197 | /** 198 | * 图片转文字 199 | * 200 | * @return 201 | */ 202 | public Object imgToText(MultipartFile file) { 203 | 204 | if (file.isEmpty()) { 205 | throw new CustomException(ExceptionCodeEnums.PARAM_NULL); 206 | } 207 | 208 | String accessToken = getBaiduAccessToken(); 209 | 210 | MultiValueMap headers = new LinkedMultiValueMap<>(); 211 | headers.add("Content-Type", "application/x-www-form-urlencoded"); 212 | 213 | String imgStr = CommonUtils.toBaseImg64(file); 214 | 215 | MultiValueMap params = new LinkedMultiValueMap<>(); 216 | params.add("image", imgStr); 217 | String result = HttpUtil 218 | .post(MessageFormat.format(UrlConfig.BAIDU_IMG_TO_TEXT_URL, accessToken), params, 219 | headers); 220 | return JSONObject.parseObject(result); 221 | 222 | } 223 | 224 | 225 | /** 226 | * 获取百度AccessToken 227 | * 228 | * @return 229 | */ 230 | private String getBaiduAccessToken() { 231 | String accessToken = redistUtil.getString(RedisKeyConfig.BAIDU_ACCESS_TOKEN_KEY); 232 | 233 | if (StringUtils.isEmpty(accessToken)) { 234 | MultiValueMap params = new LinkedMultiValueMap<>(); 235 | params.add("grant_type", "client_credentials"); 236 | params.add("client_id", baiduConfig.getApiKey()); 237 | params.add("client_secret", baiduConfig.getSecretKey()); 238 | try { 239 | String result = HttpUtil.post(UrlConfig.BAIDU_ACCESS_TOKEN_URL, params); 240 | JSONObject jsonObject = JSONObject.parseObject(result); 241 | accessToken = jsonObject.getString("access_token"); 242 | //设置20天过期, 百度accessToken过期时间在一个月左右 243 | redistUtil.setString(RedisKeyConfig.BAIDU_ACCESS_TOKEN_KEY, accessToken, 1728000L); 244 | } catch (Exception e) { 245 | throw new CustomException(ExceptionCodeEnums.ERROR, e.getMessage()); 246 | } 247 | } 248 | 249 | return accessToken; 250 | } 251 | 252 | /** 253 | * 添加留言 254 | * 255 | * @param msg 256 | * @param msgId 257 | * @param userId 258 | * @return 259 | */ 260 | @Transactional 261 | public void addMsgBoard(String msg, String msgId, String userId) { 262 | if (StringUtils.isEmpty(msgId)) { 263 | msgId = "0"; 264 | } 265 | TextBoard textBoard = TextBoard.builder() 266 | .userId(userId) 267 | .parentId(msgId) 268 | .content(msg).build(); 269 | textBoardRepository.save(textBoard); 270 | } 271 | 272 | /** 273 | * 查询留言列表 274 | * 275 | * @param pageNo 276 | * @param pageSize 277 | * @param userId 278 | * @return 279 | */ 280 | public Object findMsgBoard(int pageNo, int pageSize, String userId) { 281 | 282 | //查询留言 283 | List> list = textBoardRepository 284 | .findAllByPage(pageNo * pageSize, pageSize, userId); 285 | list = CommonUtils.toCamelCase(list); 286 | List ids = list.stream().map(e -> e.get("id").toString()) 287 | .collect(Collectors.toList()); 288 | //查询所有回复 289 | List> replyList = textBoardRepository.findAllByParentIds(ids, userId); 290 | 291 | //分组 292 | Map>> map = replyList.stream() 293 | .collect(Collectors.groupingBy(e -> e.get("parentId").toString())); 294 | 295 | List> finalList = list; 296 | map.forEach((k, v) -> { 297 | finalList.forEach(e -> { 298 | if (e.get("id").toString().equals(k)) { 299 | e.put("reply", v); 300 | } 301 | }); 302 | }); 303 | return finalList; 304 | } 305 | 306 | /** 307 | * 留言点赞 308 | * 309 | * @param msgId 310 | * @param userId 311 | */ 312 | @Transactional 313 | public void msgBoardPraise(String msgId, String userId) { 314 | 315 | //查询是否已经点赞 316 | int count = textBoardPraiseRepository.findParaiseRecordCount(userId, msgId); 317 | if (count > 0) { 318 | throw new CustomException(ExceptionCodeEnums.TEXT_BOARD_PRAISE_EXISTS); 319 | } 320 | //保存点赞记录 321 | TextBoardPraise textBoardPraise = TextBoardPraise.builder() 322 | .textBoardId(msgId) 323 | .userId(userId) 324 | .build(); 325 | textBoardPraiseRepository.save(textBoardPraise); 326 | 327 | textBoardRepository.addPraiseCount(msgId); 328 | } 329 | 330 | /** 331 | * 添加舔狗日记 332 | * 333 | * @param texts 334 | * @return 335 | */ 336 | public Object addGogText(List texts) { 337 | final int[] count = {0}; 338 | if (null != texts && texts.size() > 0) { 339 | texts.forEach(e -> { 340 | if (StringUtils.isEmpty(e)) { 341 | return; 342 | } 343 | DogText dogTextContent = dogTextRepository.findByContent(e); 344 | if (null == dogTextContent) { 345 | DogText dogText = DogText.builder() 346 | .content(e) 347 | .build(); 348 | dogTextRepository.save(dogText); 349 | count[0]++; 350 | } 351 | }); 352 | } 353 | return count[0]; 354 | } 355 | 356 | 357 | /** 358 | * 跨域接口 359 | * 360 | * @param url 361 | * @return 362 | */ 363 | public Object crossDomain(String url) { 364 | String result = HttpUtil.get(url, null); 365 | return JSONObject.parseObject(result); 366 | } 367 | 368 | 369 | /** 370 | * 验证邮箱是否存在 371 | * 372 | * @param email 373 | */ 374 | public boolean emailIsExist(String email) { 375 | User u = userRepository.findByEmail(email); 376 | if (null != u) { 377 | return true; 378 | } 379 | return false; 380 | } 381 | 382 | /** 383 | * 发送验证码 384 | * 385 | * @param email 386 | * @return 387 | */ 388 | @Transactional 389 | public void sendCode(String email) { 390 | 391 | //限制24小时10次 392 | String dayCountString = redistUtil.getString("DAY" + email); 393 | int dayCount = null == dayCountString ? 0 : Integer.parseInt(dayCountString); 394 | if (dayCount >= 10) { 395 | throw new CustomException(UserCodeEnums.DAY_MAX_SEND_EMAIL_SEND_COUNT); 396 | } 397 | if (dayCount == 0) { 398 | redistUtil.incr("DAY" + email, 3600 * 24); 399 | } else { 400 | redistUtil.incr("DAY" + email); 401 | } 402 | 403 | //每分钟三次 404 | String minuteCountString = redistUtil.getString("MINUTE" + email); 405 | int minuteCount = null == minuteCountString ? 0 : Integer.parseInt(minuteCountString); 406 | if (minuteCount > 2) { 407 | throw new CustomException(UserCodeEnums.MINUTE_MAX_SEND_EMAIL_SEND_COUNT); 408 | } else { 409 | redistUtil.incr("MINUTE" + email, 58); 410 | } 411 | 412 | //开始发送 413 | //过期时间5分钟 414 | String code = CommonUtils.getRandomCodeByCount(4); 415 | VerificationCode vc = VerificationCode.builder().code(code).email(email) 416 | .deadline(new Timestamp(new Date().getTime() + 5 * 60 * 1000)).build(); 417 | verificationCodeRepository.save(vc); 418 | 419 | //发送邮件 420 | emailUtil.sendMail(email, "小破站 | 验证码", emailUtil.sendCodeHtml(email, code)); 421 | } 422 | 423 | /** 424 | * 注册 425 | * 426 | * @param r 427 | */ 428 | @Transactional 429 | public void register(RegisterBo r) { 430 | 431 | if (emailIsExist(r.getEmail())) { 432 | throw new CustomException(UserCodeEnums.EMAIL_EXIST); 433 | } 434 | 435 | //验证邮件验证码 436 | validEmailAndCode(r.getEmail(), r.getCode().toUpperCase()); 437 | 438 | //注册 439 | User user = User.builder().email(r.getEmail()) 440 | .password(MD5Util.md5Encrypt32Upper(r.getPassword())).build(); 441 | userRepository.save(user); 442 | } 443 | 444 | /** 445 | * 登录 446 | * 447 | * @param l 448 | * @return 449 | */ 450 | public Object login(LoginBo l) { 451 | User user = userRepository.findByEmail(l.getEmail()); 452 | 453 | if (null == user) { 454 | throw new CustomException(UserCodeEnums.USER_PSW_ERROR); 455 | } 456 | if (!emailIsExist(user.getEmail())) { 457 | throw new CustomException(UserCodeEnums.USER_PSW_ERROR); 458 | } 459 | if (!user.getPassword().equals(MD5Util.md5Encrypt32Upper(l.getPassword()))) { 460 | throw new CustomException(UserCodeEnums.USER_PSW_ERROR); 461 | } 462 | 463 | UserVo u = JSONObject.parseObject(JSON.toJSONString(user), UserVo.class); 464 | u.setToken(jwtUtil.createJWT(user.getId())); 465 | return u; 466 | } 467 | 468 | /** 469 | * 忘记密码 470 | * 471 | * @param f 472 | * @return 473 | */ 474 | @Transactional 475 | public void forgetPassword(ForgetPasswordBo f) { 476 | 477 | //验证邮件验证码 478 | validEmailAndCode(f.getEmail(), f.getCode().toUpperCase()); 479 | 480 | User user = userRepository.findByEmail(f.getEmail()); 481 | user.setPassword(MD5Util.md5Encrypt32Upper(f.getPassword())); 482 | userRepository.save(user); 483 | } 484 | 485 | /** 486 | * 验证邮件验证码 487 | * 488 | * @param email 489 | * @param code 490 | */ 491 | @Transactional 492 | public void validEmailAndCode(String email, String code) { 493 | VerificationCode vc = verificationCodeRepository 494 | .findByEmailAndCodeAndUsed(email, code, false); 495 | if (null == vc) { 496 | throw new CustomException(UserCodeEnums.VERIFICATION_CODE_ERROR); 497 | } 498 | if (vc.getDeadline().before(new Date())) { 499 | throw new CustomException(UserCodeEnums.VERIFICATION_CODE_INVALID); 500 | } 501 | //验证码被使用 502 | vc.setUsed(true); 503 | verificationCodeRepository.save(vc); 504 | } 505 | 506 | /** 507 | * 查询实况天气 508 | * 509 | * @param weatherId 510 | * @return 511 | */ 512 | public Object findWeatherNow(String weatherId) { 513 | String result = HttpUtil 514 | .get(MessageFormat.format(UrlConfig.HEFENG_WEATHER_NOW_URL, weatherId, hefengKey), 515 | null, null); 516 | return JSONObject.parseObject(result); 517 | } 518 | 519 | 520 | } 521 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.service; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.wpp.devtools.domain.bo.AddSubscribeBo; 5 | import com.wpp.devtools.domain.bo.NotebookBo; 6 | import com.wpp.devtools.domain.bo.SaveUserInfoBo; 7 | import com.wpp.devtools.domain.entity.Notebook; 8 | import com.wpp.devtools.domain.entity.Subscribe; 9 | import com.wpp.devtools.domain.entity.SubscribeRecord; 10 | import com.wpp.devtools.domain.entity.User; 11 | import com.wpp.devtools.enums.ExceptionCodeEnums; 12 | import com.wpp.devtools.exception.CustomException; 13 | import com.wpp.devtools.repository.ActivityRepository; 14 | import com.wpp.devtools.repository.NotebookRepository; 15 | import com.wpp.devtools.repository.SubscribeRecordRepository; 16 | import com.wpp.devtools.repository.SubscribeRepository; 17 | import com.wpp.devtools.repository.UserRepository; 18 | import com.wpp.devtools.util.CommonUtils; 19 | import com.wpp.devtools.util.EmailUtil; 20 | import com.wpp.devtools.util.JpaUpdateUtil; 21 | import java.util.List; 22 | import java.util.Map; 23 | import org.apache.commons.lang3.StringUtils; 24 | import org.springframework.beans.factory.annotation.Autowired; 25 | import org.springframework.stereotype.Service; 26 | import org.springframework.transaction.annotation.Transactional; 27 | 28 | @Service 29 | public class UserService { 30 | 31 | @Autowired 32 | private ActivityRepository activityRepository; 33 | 34 | @Autowired 35 | private SubscribeRepository subscribeRepository; 36 | 37 | @Autowired 38 | private SubscribeRecordRepository subscribeRecordRepository; 39 | 40 | @Autowired 41 | private UnAuthService unAuthService; 42 | 43 | @Autowired 44 | private EmailUtil emailUtil; 45 | 46 | @Autowired 47 | private NotebookRepository notebookRepository; 48 | 49 | @Autowired 50 | private UserRepository userRepository; 51 | 52 | /** 53 | * 保存用户信息 54 | * @param u 55 | * @param userId 56 | */ 57 | public void saveUserInfo(SaveUserInfoBo u, String userId) { 58 | User user = JSON.parseObject(JSON.toJSONString(u), User.class); 59 | User userOld = userRepository.findById(userId).orElse(null); 60 | JpaUpdateUtil.copyNullProperties(userOld, user); 61 | userRepository.save(user); 62 | } 63 | 64 | 65 | /** 66 | * 获取用户信息 67 | * @param userId 68 | * @return 69 | */ 70 | public Object findUserInfo(String userId) { 71 | return userRepository.findById(userId).orElse(null); 72 | 73 | } 74 | 75 | /** 76 | * 查询活动列表 77 | * 78 | * @return 79 | */ 80 | public Object findActivityList() { 81 | return activityRepository.findAllByOrderBySort(); 82 | } 83 | 84 | /** 85 | * 添加订阅 86 | * 87 | * @param a 88 | * @param userId 89 | * @return 90 | */ 91 | public void addSubscribe(AddSubscribeBo a, 92 | String userId) { 93 | 94 | Subscribe s = subscribeRepository.findCancelByEmail(a.getEmail()); 95 | if (null != s) { 96 | //判断是否已经存在 97 | if(StringUtils.isBlank(a.getId())) { 98 | throw new CustomException(ExceptionCodeEnums.GOD_EMAIL_EXISTS); 99 | } 100 | //判断是否被取消订阅 101 | if(s.isCancel()) { 102 | throw new CustomException(ExceptionCodeEnums.GOD_EMAIL_CANCEL); 103 | } 104 | } 105 | 106 | Subscribe subscribe = new Subscribe(); 107 | if (StringUtils.isNoneBlank(a.getId())) { 108 | subscribe = subscribeRepository.findById(a.getId()).orElse(new Subscribe()); 109 | } 110 | Subscribe newSubscribe = JSON.parseObject(JSON.toJSONString(a), Subscribe.class); 111 | JpaUpdateUtil.copyNullProperties(subscribe, newSubscribe); 112 | newSubscribe.setActivityName(String.join(",", a.getActivityName())); 113 | newSubscribe.setUserId(userId); 114 | subscribeRepository.save(newSubscribe); 115 | } 116 | 117 | /** 118 | * 查询订阅 119 | * 120 | * @param userId 121 | * @return 122 | */ 123 | public Object findSubscribe(String userId) { 124 | List> list = subscribeRepository.findList(userId); 125 | list = CommonUtils.toCamelCase(list); 126 | list.forEach(e -> { 127 | e.put("activityName", e.get("activityName").toString().split(",")); 128 | }); 129 | return list; 130 | } 131 | 132 | /** 133 | * 发送订阅 134 | */ 135 | public int sendSubscribe() { 136 | List list = subscribeRepository.findAllSubscribe(CommonUtils.getThisTimeHour()); 137 | list.forEach(e -> { 138 | if (e.getActivityName().contains("日记")) { 139 | String content = unAuthService 140 | .getDoglickingDiary(); 141 | emailUtil.sendMail(e.getEmail(), "小破站 | 日记", 142 | emailUtil.sendDiaryHtml(content, e.getGodNickName(), e.getNickName(), e.getId())); 143 | SubscribeRecord s = SubscribeRecord.builder().subscribeId(e.getId()).build(); 144 | subscribeRecordRepository.save(s); 145 | } 146 | }); 147 | return list.size(); 148 | } 149 | 150 | 151 | /** 152 | * 取消订阅 153 | * 154 | * @param id 155 | * @param cancel 156 | */ 157 | public void cancelSubscribe(String id, Boolean cancel) { 158 | Subscribe subscribe = subscribeRepository.findById(id).orElse(null); 159 | if (null == subscribe) { 160 | throw new CustomException(ExceptionCodeEnums.PARAM_ERROR); 161 | } 162 | subscribe.setCancel(cancel); 163 | subscribeRepository.save(subscribe); 164 | } 165 | 166 | /** 167 | * 启用禁用订阅 168 | * @param id 169 | * @param enabled 170 | */ 171 | public void enabledSubscribe(String id, Boolean enabled) { 172 | Subscribe subscribe = subscribeRepository.findById(id).orElse(null); 173 | if (null == subscribe) { 174 | throw new CustomException(ExceptionCodeEnums.PARAM_ERROR); 175 | } 176 | subscribe.setEnabled(enabled); 177 | subscribeRepository.save(subscribe); 178 | } 179 | 180 | /** 181 | * 删除订阅 182 | * @param id 183 | */ 184 | @Transactional 185 | public void delSubscribe(String id) { 186 | subscribeRepository.deleteById(id); 187 | } 188 | 189 | /** 190 | * 保存笔记 191 | * @param userId 192 | * @param n 193 | */ 194 | @Transactional 195 | public void saveNotebook(String userId, NotebookBo n) { 196 | Notebook notebook = JSON.parseObject(JSON.toJSONString(n), Notebook.class); 197 | notebook.setUserId(userId); 198 | 199 | if(StringUtils.isNoneBlank(n.getId())) { 200 | Notebook oldNoteBook = notebookRepository.findById(n.getId()).orElse(new Notebook()); 201 | JpaUpdateUtil.copyNullProperties(oldNoteBook, notebook); 202 | } 203 | notebookRepository.save(notebook); 204 | } 205 | 206 | /** 207 | * 删除笔记 208 | * @param id 209 | */ 210 | @Transactional 211 | public void delNotebook(String id) { 212 | notebookRepository.deleteById(id); 213 | } 214 | 215 | /** 216 | * 查询笔记列表 217 | * @param userId 218 | * @return 219 | */ 220 | public Object findNotebookList(String userId) { 221 | return notebookRepository.findAllByUserIdOrderBySortAsc(userId); 222 | } 223 | 224 | /** 225 | * 修改笔记排序 226 | * @param id 227 | * @param oldIndex 228 | * @param newIndex 229 | */ 230 | @Transactional 231 | public void updateNotebookIndex(String id, String userId, long oldIndex, long newIndex) { 232 | if(oldIndex == newIndex) { 233 | return; 234 | } 235 | 236 | long deviation = oldIndex - newIndex > 0 ? 1 : -1; 237 | if(deviation > 0) { 238 | //向上移动 239 | notebookRepository.updateSortAllTopById(userId, deviation, oldIndex, newIndex); 240 | }else{ 241 | //向下移动 242 | notebookRepository.updateSortAllDownById(userId, deviation, oldIndex, newIndex); 243 | } 244 | notebookRepository.updateSortById(id, oldIndex, newIndex); 245 | } 246 | 247 | 248 | } 249 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/util/CommonUtils.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.util; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.google.common.base.CaseFormat; 5 | import com.wpp.devtools.enums.ExceptionCodeEnums; 6 | import com.wpp.devtools.exception.CustomException; 7 | import java.io.IOException; 8 | import java.text.SimpleDateFormat; 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.Calendar; 12 | import java.util.Collections; 13 | import java.util.Date; 14 | import java.util.HashMap; 15 | import java.util.List; 16 | import java.util.Map; 17 | import javax.servlet.http.HttpServletRequest; 18 | import org.apache.commons.lang3.StringUtils; 19 | import org.springframework.web.multipart.MultipartFile; 20 | import sun.misc.BASE64Encoder; 21 | 22 | /** 23 | * @program: volvo-server 24 | * @description: 25 | * @author: wpp 26 | * @create: 2020-07-14 27 | **/ 28 | public class CommonUtils { 29 | 30 | /** 31 | * map key转成驼峰 32 | * 33 | * @param map 34 | * @param clazz 35 | * @param 36 | * @return 37 | */ 38 | public static T toCamelCase(Map map, Class clazz) { 39 | Map var = new HashMap(); 40 | map.forEach((k, v) -> { 41 | String s = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, k); 42 | var.put(s, v); 43 | }); 44 | return JSON.parseObject(JSON.toJSONString(var), clazz); 45 | } 46 | 47 | 48 | /** 49 | * List map key转成驼峰 50 | * 51 | * @param list 52 | * @return 53 | */ 54 | public static List> toCamelCase(List> list) { 55 | List> listCopy = new ArrayList<>(); 56 | list.stream().forEach(e -> { 57 | Map var = new HashMap(); 58 | e.forEach((k, v) -> { 59 | String s = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, k); 60 | var.put(s, v); 61 | }); 62 | listCopy.add(var); 63 | }); 64 | return listCopy; 65 | } 66 | 67 | 68 | /** 69 | * 获取指定格式时间字符串 70 | * @param date 71 | * @param format 72 | * @return 73 | */ 74 | public static String getTimeStr(Date date, String format){ 75 | SimpleDateFormat sf = new SimpleDateFormat(format); 76 | return sf.format(date); 77 | } 78 | 79 | 80 | /** 81 | * 图片转base64 82 | * 83 | * @param file 84 | * @return 85 | */ 86 | public static String toBaseImg64(MultipartFile file) { 87 | BASE64Encoder encode = new BASE64Encoder(); 88 | try { 89 | return encode.encode(file.getBytes()).replaceAll("[\\s*\t\n\r]", ""); 90 | } catch (IOException e) { 91 | throw new CustomException(ExceptionCodeEnums.ERROR, e.getMessage()); 92 | } 93 | } 94 | 95 | /** 96 | * 获取客户端ip 97 | */ 98 | public static String getIpAddr(HttpServletRequest request) { 99 | String ip = request.getHeader("X-Real-IP"); 100 | if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) { 101 | return ip; 102 | } 103 | ip = request.getHeader("X-Forwarded-For"); 104 | if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) { 105 | // 多次反向代理后会有多个IP值,第一个为真实IP。 106 | int index = ip.indexOf(','); 107 | if (index != -1) { 108 | return ip.substring(0, index); 109 | } else { 110 | return ip; 111 | } 112 | } else { 113 | return request.getRemoteAddr(); 114 | } 115 | } 116 | 117 | /** 118 | * 获取随机验证码 119 | * @param count 120 | * @return 121 | */ 122 | public static String getRandomCodeByCount(int count) { 123 | String[] beforeShuffle = new String[]{"1", "2", "3", "4", "5", "6", "7", 124 | "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", 125 | "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", 126 | "W", "X", "Y", "Z"}; 127 | List list = Arrays.asList(beforeShuffle); 128 | Collections.shuffle(list); 129 | StringBuilder sb = new StringBuilder(); 130 | for (int i = 0; i < count; i++) { 131 | sb.append(list.get(i)); 132 | } 133 | return sb.toString(); 134 | } 135 | 136 | public static int getThisTimeHour() { 137 | Calendar calendar = Calendar.getInstance(); 138 | return calendar.get(calendar.HOUR_OF_DAY); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/util/EmailUtil.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.util; 2 | 3 | import com.wpp.devtools.enums.ExceptionCodeEnums; 4 | import com.wpp.devtools.exception.CustomException; 5 | import java.util.Date; 6 | import java.util.Properties; 7 | import javax.mail.BodyPart; 8 | import javax.mail.Message; 9 | import javax.mail.MessagingException; 10 | import javax.mail.Multipart; 11 | import javax.mail.Session; 12 | import javax.mail.Transport; 13 | import javax.mail.internet.InternetAddress; 14 | import javax.mail.internet.MimeBodyPart; 15 | import javax.mail.internet.MimeMessage; 16 | import javax.mail.internet.MimeMultipart; 17 | import lombok.extern.slf4j.Slf4j; 18 | import org.apache.commons.lang3.StringUtils; 19 | import org.springframework.beans.factory.annotation.Value; 20 | import org.springframework.stereotype.Component; 21 | 22 | /** 23 | * @program: volvo-server 24 | * @description: 25 | * @author: wpp 26 | * @create: 2020-07-07 27 | **/ 28 | @Component 29 | @Slf4j 30 | public class EmailUtil { 31 | 32 | // 发件人邮箱地址 33 | @Value("${EMAIL.FROM}") 34 | private String from; 35 | 36 | // HOST地址 37 | @Value("${EMAIL.HOST}") 38 | private String host; 39 | 40 | // 端口 41 | @Value("${EMAIL.PORT}") 42 | private String port; 43 | 44 | 45 | // 发件人邮箱客户端授权码 46 | @Value("${EMAIL.PASSWORD}") 47 | private String password; 48 | 49 | /** 50 | * 发送验证信息的邮件 51 | * 52 | * @param to 53 | * @param text 54 | * @param title 55 | */ 56 | public void sendMail(String to, String title, String text) { 57 | if(StringUtils.isNoneBlank(to)) { 58 | Properties props = new Properties(); 59 | props.setProperty("mail.smtp.host", host); // 设置发送邮件的邮件服务器的属性(这里使用网易的smtp服务器) 60 | props.put("mail.smtp.host", host); // 需要经过授权,也就是有户名和密码的校验,这样才能通过验证(一定要有这一条) 61 | props.put("mail.smtp.auth", true); // 用刚刚设置好的props对象构建一个session 62 | props.put("mail.smtp.ssl.enable", true); 63 | props.put("mail.smtp.port", port); 64 | Session session = Session.getDefaultInstance(props); // 有了这句便可以在发送邮件的过程中在console处显示过程信息,供调试使 65 | // 用(你可以在控制台(console)上看到发送邮件的过程) 66 | session.setDebug(false); // 用session为参数定义消息对象 67 | MimeMessage message = new MimeMessage(session); // 加载发件人地址 68 | try { 69 | message.setFrom(new InternetAddress(from)); 70 | message.addRecipient(Message.RecipientType.TO, new InternetAddress(to)); // 加载收件人地址 71 | message.setSubject(title); // 加载标题 72 | Multipart multipart = new MimeMultipart(); // 向multipart对象中添加邮件的各个部分内容,包括文本内容和附件 73 | BodyPart contentPart = new MimeBodyPart(); // 设置邮件的文本内容 74 | contentPart.setContent(text, "text/html;charset=utf-8"); 75 | multipart.addBodyPart(contentPart); 76 | message.setContent(multipart); 77 | message.saveChanges(); // 保存变化 78 | Transport transport = session.getTransport("smtp"); // 连接服务器的邮箱 79 | transport.connect(host, from, password); // 把邮件发送出去 80 | transport.sendMessage(message, message.getAllRecipients()); 81 | transport.close(); 82 | } catch (MessagingException e) { 83 | log.error("邮件发送失败 to: {}", to, e); 84 | throw new CustomException(ExceptionCodeEnums.EMAIL_SEND_ERROR); 85 | } 86 | } 87 | 88 | } 89 | 90 | /** 91 | * 发送短信验证码样式 92 | * 93 | * @param email 94 | * @param code 95 | * @return 96 | */ 97 | public String sendCodeHtml(String email, String code) { 98 | String time = CommonUtils.getTimeStr(new Date(), "yyyy-MM-dd HH:mm:ss"); 99 | String html = 100 | " \n" + 109 | " \n" + 110 | " \n" + 111 | " \n" + 128 | " \n" + 129 | " \n" + 130 | " \n" + 194 | " \n" + 195 | " \n" + 196 | "
\n" 112 | + 113 | "

小破站

\n" + 119 | "

\n" + 120 | " wangpinpin.com\n" + 126 | "

\n" + 127 | "
\n" + 138 | " \n" 139 | + 140 | " \n" + 141 | " \n" + 142 | " \n" + 146 | " \n" + 147 | " \n" + 148 | " \n" + 152 | " \n" + 153 | " \n" + 181 | " \n" + 182 | " \n" + 183 | " \n" + 191 | " \n" + 192 | "
\n" + 143 | " 舔狗每日报道\n" 144 | + 145 | "
您登录邮箱 " 149 | + email 150 | + " 所需的验证码为: " 151 | + code + "
\n" + 154 | " \n" 155 | + 156 | " \n" + 157 | " \n" + 158 | " \n" + 177 | " \n" + 178 | " \n" + 179 | "
\n" + 159 | "
\n" + 160 | "
\n" + 161 | " \n" + 165 | " \n" + 168 | " \n" + 169 | " \n" + 171 | " \n" + 172 | " \n" 173 | + 174 | " \n" + 175 | "
" 170 | + time + "
 
\n" + 176 | "
\n" + 180 | "
\n" 184 | + 185 | "
\n" + 186 | "
该验证码有效期为5分钟\n" + 187 | "
\n" + 188 | "
请勿将验证码展示给他人\n" + 189 | "
\n" + 190 | "
\n" + 193 | "
\n"; 197 | return html; 198 | } 199 | 200 | public String sendDiaryHtml(String content, String godNickName, String from, String id) { 201 | String time = CommonUtils.getTimeStr(new Date(), "yyyy-MM-dd HH:mm"); 202 | 203 | //署名 204 | String fromDiv = ""; 205 | if (StringUtils.isNoneBlank(from)) { 206 | fromDiv = "" + from + ""; 207 | } 208 | 209 | String html = 210 | " \n" + 219 | " \n" + 220 | " \n" + 221 | " \n" + 238 | " \n" + 239 | " \n" + 240 | " \n" + 319 | " \n" + 320 | " \n" + 321 | "
\n" 222 | + 223 | "

小破站

\n" + 229 | "

\n" + 230 | " wangpinpin.com\n" + 236 | "

\n" + 237 | "
\n" + 248 | " \n" 249 | + 250 | " \n" + 251 | " \n" + 252 | " \n" + 256 | " \n" + 257 | " \n" + 258 | " \n" + 260 | " \n" + 261 | " \n" + 263 | " \n" + 264 | " \n" + 297 | " \n" + 298 | " \n" + 299 | " \n" + 315 | " \n" + 316 | " \n" + 317 | "
\n" + 253 | " 舔狗每日报道\n" 254 | + 255 | "
Dear " 259 | + godNickName + "
" 262 | + content + "
\n" + 265 | " \n" 266 | + 267 | " \n" + 268 | " \n" + 269 | " \n" + 293 | " \n" + 294 | " \n" + 295 | "
\n" + 270 | "
\n" + 271 | "
\n" + 272 | " \n" + 276 | " \n" + 279 | fromDiv + 280 | " \n" + 281 | " \n" + 282 | " \n" + 284 | " \n" + 285 | " \n" 286 | + 287 | " \n" + 288 | " \n" 289 | + 290 | " \n" + 291 | "
" 283 | + time + "
今天也是一只合格的舔狗呢
 
\n" + 292 | "
\n" + 296 | "
\n" 300 | + 301 | "
\n" + 302 | "
\n" + 303 | " 留言\n" 304 | + 305 | "
\n" + 306 | "
\n" + 307 | " 帮他人订阅\n" 308 | + 309 | "
\n" + 310 | "
\n" + 311 | " 点击退订\n" 313 | + 314 | "
\n" + 318 | "
\n"; 322 | return html; 323 | } 324 | } 325 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/util/HttpUtil.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.util; 2 | 3 | import org.springframework.http.HttpEntity; 4 | import org.springframework.http.HttpHeaders; 5 | import org.springframework.http.HttpMethod; 6 | import org.springframework.http.MediaType; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.util.LinkedMultiValueMap; 9 | import org.springframework.util.MultiValueMap; 10 | import org.springframework.web.client.RestTemplate; 11 | 12 | /** 13 | * http请求工具类 14 | * 15 | */ 16 | public class HttpUtil { 17 | /** 18 | * get请求 19 | * 20 | * @param url 21 | * @param params 请求参数 22 | * @return 23 | */ 24 | public static String get(String url, MultiValueMap params) { 25 | return get(url, params, null); 26 | } 27 | 28 | /** 29 | * get请求 30 | * 31 | * @param url 32 | * @param params 请求参数 33 | * @param headers 请求头 34 | * @return 35 | */ 36 | public static String get(String url, MultiValueMap params, MultiValueMap headers) { 37 | return request(url, params, headers, HttpMethod.GET); 38 | } 39 | 40 | /** 41 | * post请求 42 | * 43 | * @param url 44 | * @param params 请求参数 45 | * @return 46 | */ 47 | public static String post(String url, MultiValueMap params) { 48 | return post(url, params, null); 49 | } 50 | 51 | /** 52 | * post请求 53 | * 54 | * @param url 55 | * @param params 请求参数 56 | * @param headers 请求头 57 | * @return 58 | */ 59 | public static String post(String url, MultiValueMap params, MultiValueMap headers) { 60 | return request(url, params, headers, HttpMethod.POST); 61 | } 62 | 63 | /** 64 | * put请求 65 | * 66 | * @param url 67 | * @param params 请求参数 68 | * @return 69 | */ 70 | public static String put(String url, MultiValueMap params) { 71 | return put(url, params, null); 72 | } 73 | 74 | /** 75 | * put请求 76 | * 77 | * @param url 78 | * @param params 请求参数 79 | * @param headers 请求头 80 | * @return 81 | */ 82 | public static String put(String url, MultiValueMap params, MultiValueMap headers) { 83 | return request(url, params, headers, HttpMethod.PUT); 84 | } 85 | 86 | /** 87 | * delete请求 88 | * 89 | * @param url 90 | * @param params 请求参数 91 | * @return 92 | */ 93 | public static String delete(String url, MultiValueMap params) { 94 | return delete(url, params, null); 95 | } 96 | 97 | /** 98 | * delete请求 99 | * 100 | * @param url 101 | * @param params 请求参数 102 | * @param headers 请求头 103 | * @return 104 | */ 105 | public static String delete(String url, MultiValueMap params, MultiValueMap headers) { 106 | return request(url, params, headers, HttpMethod.DELETE); 107 | } 108 | 109 | /** 110 | * 表单请求 111 | * 112 | * @param url 113 | * @param params 请求参数 114 | * @param headers 请求头 115 | * @param method 请求方式 116 | * @return 117 | */ 118 | public static String request(String url, MultiValueMap params, MultiValueMap headers, HttpMethod method) { 119 | if (params == null) { 120 | params = new LinkedMultiValueMap<>(); 121 | } 122 | return request(url, params, headers, method, MediaType.APPLICATION_FORM_URLENCODED); 123 | } 124 | 125 | /** 126 | * http请求 127 | * 128 | * @param url 129 | * @param params 请求参数 130 | * @param headers 请求头 131 | * @param method 请求方式 132 | * @param mediaType 参数类型 133 | * @return 134 | */ 135 | public static String request(String url, Object params, MultiValueMap headers, HttpMethod method, MediaType mediaType) { 136 | if (url == null || url.trim().isEmpty()) { 137 | return null; 138 | } 139 | RestTemplate client = new RestTemplate(); 140 | // header 141 | HttpHeaders httpHeaders = new HttpHeaders(); 142 | if (headers != null) { 143 | httpHeaders.addAll(headers); 144 | } 145 | // 提交方式:表单、json 146 | httpHeaders.setContentType(mediaType); 147 | HttpEntity httpEntity = new HttpEntity(params, httpHeaders); 148 | ResponseEntity response = client.exchange(url, method, httpEntity, String.class); 149 | return response.getBody(); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/util/JWTUtil.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.util; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.wpp.devtools.config.JWTConfig; 6 | import com.wpp.devtools.enums.ExceptionCodeEnums; 7 | import com.wpp.devtools.exception.CustomException; 8 | import io.jsonwebtoken.Claims; 9 | import io.jsonwebtoken.ExpiredJwtException; 10 | import io.jsonwebtoken.JwtBuilder; 11 | import io.jsonwebtoken.Jwts; 12 | import io.jsonwebtoken.SignatureAlgorithm; 13 | import java.security.Key; 14 | import java.util.Date; 15 | import javax.crypto.spec.SecretKeySpec; 16 | import javax.xml.bind.DatatypeConverter; 17 | import lombok.extern.slf4j.Slf4j; 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.stereotype.Component; 20 | 21 | /** 22 | * @program: devtools-server 23 | * @description: 24 | * @author: wpp 25 | * @create: 2020-07-06 26 | **/ 27 | @Slf4j 28 | @Component 29 | public class JWTUtil { 30 | 31 | @Autowired 32 | private JWTConfig jwtConfig; 33 | /** 34 | * 解析jwt 35 | */ 36 | public JSONObject parseJWT(String token) { 37 | if (null == token || !token.startsWith(JWTConfig.JWT_BEARER)) { 38 | throw new CustomException(ExceptionCodeEnums.JWT_VALID_ERROR); 39 | } 40 | token = token.substring(6); 41 | try { 42 | Claims claims = Jwts.parser() 43 | .setSigningKey(DatatypeConverter.parseBase64Binary(jwtConfig.getJwtBase64secret())) 44 | .parseClaimsJws(token).getBody(); 45 | if (null == claims) { 46 | throw new CustomException(ExceptionCodeEnums.JWT_VALID_ERROR); 47 | } 48 | return JSONObject.parseObject(JSON.toJSONString(claims)); 49 | } catch (ExpiredJwtException e) { 50 | throw new CustomException(ExceptionCodeEnums.JWT_VALID_OVERDUE); 51 | } catch (Exception e) { 52 | throw new CustomException(ExceptionCodeEnums.JWT_ERROR); 53 | } 54 | 55 | } 56 | 57 | /** 58 | * 创建JWT 59 | * 60 | * @param userId 用户ID 61 | * @param expMillis 秒 62 | * @return 63 | */ 64 | public String createJWT(String userId, long expMillis) { 65 | if (null == userId) { 66 | throw new CustomException(ExceptionCodeEnums.ID_NULL); 67 | } 68 | SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; 69 | 70 | long nowMillis = System.currentTimeMillis(); 71 | Date now = new Date(nowMillis); 72 | 73 | //生成签名密钥 74 | byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(jwtConfig.getJwtBase64secret()); 75 | Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName()); 76 | 77 | //添加构成JWT的参数 78 | JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT") 79 | .claim(JWTConfig.JWT_USER_ID_KEY, userId) 80 | .setIssuer(JWTConfig.JWT_NAME) 81 | .setAudience(jwtConfig.getJwtClientid()) 82 | .signWith(signatureAlgorithm, signingKey); 83 | 84 | //添加Token过期时间 85 | expMillis = nowMillis + expMillis * 1000; 86 | Date exp = new Date(expMillis); 87 | builder.setExpiration(exp).setNotBefore(now); 88 | 89 | //生成JWT 90 | return JWTConfig.JWT_BEARER + builder.compact(); 91 | } 92 | 93 | /** 94 | * 创建JWT 95 | * 96 | * @param userId 97 | * @return 98 | */ 99 | public String createJWT(String userId) { 100 | long expMillis = JWTConfig.JWT_EXPIRESSECOND; 101 | return createJWT(userId, expMillis); 102 | } 103 | 104 | } -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/util/JpaUpdateUtil.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.util; 2 | 3 | import java.beans.PropertyDescriptor; 4 | import java.util.HashSet; 5 | import java.util.Set; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.BeanUtils; 8 | import org.springframework.beans.BeanWrapper; 9 | import org.springframework.beans.BeanWrapperImpl; 10 | 11 | /** 12 | * @program: volvo-server 13 | * @description: 14 | * @author: wpp 15 | * @create: 2020-07-07 16 | **/ 17 | @Slf4j 18 | public class JpaUpdateUtil { 19 | 20 | /** 21 | * 将目标源中不为空的字段过滤,将数据库中查出的数据源复制到提交的目标源中 22 | * 23 | * @param source 用id从数据库中查出来的数据源 24 | * @param target 提交的实体,目标源 25 | */ 26 | public static void copyNullProperties(Object source, Object target) { 27 | BeanUtils.copyProperties(source, target, getNoNullProperties(target)); 28 | } 29 | 30 | /** 31 | * @param target 目标源数据 32 | * @return 将目标源中不为空的字段取出 33 | */ 34 | public static String[] getNoNullProperties(Object target) { 35 | BeanWrapper srcBean = new BeanWrapperImpl(target); 36 | PropertyDescriptor[] pds = srcBean.getPropertyDescriptors(); 37 | Set noEmptyName = new HashSet<>(); 38 | for (PropertyDescriptor p : pds) { 39 | Object value = srcBean.getPropertyValue(p.getName()); 40 | if (value != null) { 41 | noEmptyName.add(p.getName()); 42 | } 43 | } 44 | String[] result = new String[noEmptyName.size()]; 45 | return noEmptyName.toArray(result); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/util/MD5Util.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.util; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.security.MessageDigest; 5 | import java.security.NoSuchAlgorithmException; 6 | import java.util.regex.Matcher; 7 | import java.util.regex.Pattern; 8 | 9 | /** 10 | * @program: volvo-server 11 | * @description: 12 | * @author: wpp 13 | * @create: 2020-07-07 14 | **/ 15 | public class MD5Util { 16 | 17 | /** 18 | * MD5加密字符串(32位大写) 19 | * 20 | * @param string 需要进行MD5加密的字符串 21 | * @return 加密后的字符串(大写) 22 | */ 23 | public static String md5Encrypt32Upper(String string) { 24 | byte[] hash; 25 | try { 26 | //创建一个MD5算法对象,并获得MD5字节数组,16*8=128位 27 | hash = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8")); 28 | } catch (NoSuchAlgorithmException e) { 29 | throw new RuntimeException("Huh, MD5 should be supported?", e); 30 | } catch (UnsupportedEncodingException e) { 31 | throw new RuntimeException("Huh, UTF-8 should be supported?", e); 32 | } 33 | 34 | //转换为十六进制字符串 35 | StringBuilder hex = new StringBuilder(hash.length * 2); 36 | for (byte b : hash) { 37 | if ((b & 0xFF) < 0x10) { 38 | hex.append("0"); 39 | } 40 | hex.append(Integer.toHexString(b & 0xFF)); 41 | } 42 | return hex.toString().toUpperCase(); 43 | } 44 | 45 | /** 46 | * MD5加密字符串(32位小写) 47 | * 48 | * @param string 需要进行MD5加密的字符串 49 | * @return 加密后的字符串(小写) 50 | */ 51 | public static String md5Encrypt32Lower(String string) { 52 | //直接上面的方法转换成小写就可以了 53 | return md5Encrypt32Upper(string).toLowerCase(); 54 | } 55 | 56 | /** 57 | * 将二进制字节数组转换为十六进制字符串 58 | * 59 | * @param bytes 二进制字节数组 60 | * @return 十六进制字符串 61 | */ 62 | public static String bytesToHex(byte[] bytes) { 63 | StringBuffer hexStr = new StringBuffer(); 64 | int num; 65 | for (int i = 0; i < bytes.length; i++) { 66 | num = bytes[i]; 67 | if (num < 0) { 68 | num += 256; 69 | } 70 | if (num < 16) { 71 | hexStr.append("0"); 72 | } 73 | hexStr.append(Integer.toHexString(num)); 74 | } 75 | return hexStr.toString().toUpperCase(); 76 | } 77 | 78 | /** 79 | * Unicode中文编码转换成字符串 80 | */ 81 | public static String unicodeToString(String str) { 82 | Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))"); 83 | Matcher matcher = pattern.matcher(str); 84 | char ch; 85 | while (matcher.find()) { 86 | ch = (char) Integer.parseInt(matcher.group(2), 16); 87 | str = str.replace(matcher.group(1), ch + ""); 88 | } 89 | return str; 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/util/RedistUtil.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.util; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.data.redis.core.StringRedisTemplate; 6 | import org.springframework.data.redis.support.atomic.RedisAtomicLong; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * @program: devtools-server 11 | * @description: 12 | * @author: wpp 13 | * @create: 2020-08-05 14 | **/ 15 | @Component 16 | public class RedistUtil { 17 | 18 | @Autowired 19 | private StringRedisTemplate stringRedisTemplate; 20 | 21 | /** 22 | * 存放string类型到hash 23 | * 24 | * @param key1 key1 25 | * @param key2 key2 26 | * @param data 数据 27 | */ 28 | public void setStringToHash(String key1,String key2, String data) { 29 | stringRedisTemplate.opsForHash().put(key1, key2, data); 30 | } 31 | 32 | /** 33 | * 获取放string类型到hash 34 | * 35 | * @param key1 key1 36 | * @param key2 key2 37 | */ 38 | public boolean getStringToHash(String key1,String key2) { 39 | return stringRedisTemplate.opsForHash().hasKey(key1, key2); 40 | } 41 | 42 | /** 43 | * 存放string类型 44 | * 45 | * @param key key 46 | * @param data 数据 47 | * @param timeout 超时间 48 | */ 49 | public void setString(String key, String data, Long timeout) { 50 | try { 51 | stringRedisTemplate.opsForValue().set(key, data); 52 | if (timeout != null) { 53 | stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS); 54 | } 55 | 56 | } catch (Exception e) { 57 | 58 | } 59 | 60 | } 61 | 62 | /** 63 | * 开启Redis 事务 64 | * 65 | * @param 66 | */ 67 | public void begin() { 68 | // 开启Redis 事务权限 69 | stringRedisTemplate.setEnableTransactionSupport(true); 70 | // 开启事务 71 | stringRedisTemplate.multi(); 72 | 73 | } 74 | 75 | /** 76 | * 提交事务 77 | * 78 | * @param 79 | */ 80 | public void exec() { 81 | // 成功提交事务 82 | stringRedisTemplate.exec(); 83 | } 84 | 85 | /** 86 | * 回滚Redis 事务 87 | */ 88 | public void discard() { 89 | stringRedisTemplate.discard(); 90 | } 91 | 92 | /** 93 | * 存放string类型 94 | * 95 | * @param key key 96 | * @param data 数据 97 | */ 98 | public void setString(String key, String data) { 99 | setString(key, data, null); 100 | } 101 | 102 | /** 103 | * 根据key查询string类型 104 | * 105 | * @param key 106 | * @return 107 | */ 108 | public String getString(String key) { 109 | String value = stringRedisTemplate.opsForValue().get(key); 110 | return value; 111 | } 112 | 113 | /** 114 | * 根据对应的key删除key 115 | * 116 | * @param key 117 | */ 118 | public Boolean delKey(String key) { 119 | return stringRedisTemplate.delete(key); 120 | 121 | } 122 | 123 | /** 124 | * key + 1 125 | * 126 | * @param key 127 | * @return 128 | */ 129 | public Long incr(String key) { 130 | RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, 131 | stringRedisTemplate.getConnectionFactory()); 132 | return entityIdCounter.getAndIncrement(); 133 | } 134 | 135 | public Long incr(String key, long seconds) { 136 | RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, 137 | stringRedisTemplate.getConnectionFactory()); 138 | Long increment = entityIdCounter.getAndIncrement(); 139 | if ((null == increment || increment.longValue() == 0) && seconds > 0) {//初始设置过期时间 140 | entityIdCounter.expire(seconds, TimeUnit.SECONDS); 141 | } 142 | return increment; 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/com/wpp/devtools/util/SSLUtil.java: -------------------------------------------------------------------------------- 1 | package com.wpp.devtools.util; 2 | 3 | import java.security.KeyManagementException; 4 | import java.security.NoSuchAlgorithmException; 5 | import java.security.cert.X509Certificate; 6 | import javax.net.ssl.HttpsURLConnection; 7 | import javax.net.ssl.SSLContext; 8 | import javax.net.ssl.TrustManager; 9 | import javax.net.ssl.X509TrustManager; 10 | 11 | /** 12 | * @program: devtools-server 13 | * @description: 14 | * @author: wpp 15 | * @create: 2020-08-14 16 | **/ 17 | public class SSLUtil { 18 | 19 | private static final TrustManager[] UNQUESTIONING_TRUST_MANAGER = new TrustManager[]{ 20 | new X509TrustManager() { 21 | public java.security.cert.X509Certificate[] getAcceptedIssuers() { 22 | return null; 23 | } 24 | 25 | public void checkClientTrusted(X509Certificate[] certs, String authType) { 26 | } 27 | 28 | public void checkServerTrusted(X509Certificate[] certs, String authType) { 29 | } 30 | } 31 | }; 32 | 33 | public static void turnOffSslChecking() 34 | throws NoSuchAlgorithmException, KeyManagementException { 35 | // Install the all-trusting trust manager 36 | final SSLContext sc = SSLContext.getInstance("SSL"); 37 | sc.init(null, UNQUESTIONING_TRUST_MANAGER, null); 38 | HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 39 | } 40 | 41 | public static void turnOnSslChecking() throws KeyManagementException, NoSuchAlgorithmException { 42 | // Return it to the initial state (discovered by reflection, now hardcoded) 43 | SSLContext.getInstance("SSL").init(null, null, null); 44 | } 45 | 46 | private SSLUtil() { 47 | throw new UnsupportedOperationException("Do not instantiate libraries."); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: dev 4 | datasource: 5 | url: jdbc:mysql://XXXX:3306/devtools?useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT&zeroDateTimeBehavior=convertToNull&useSSL=false 6 | username: XXX 7 | password: XXX 8 | driver-class-name: com.mysql.cj.jdbc.Driver 9 | redis: 10 | host: XXX 11 | port: 6379 12 | password: XXX 13 | jpa: 14 | hibernate: 15 | ddl-auto: update 16 | naming: 17 | physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy 18 | database-platform: org.hibernate.dialect.MySQL5InnoDBDialect 19 | application: 20 | name: devtools-server 21 | servlet: 22 | multipart: 23 | max-file-size: 10MB 24 | max-request-size: 100MB 25 | jackson: 26 | date-format: yyyy-MM-dd HH:mm:ss 27 | time-zone: GMT+8 28 | server: 29 | port: 8001 30 | log: 31 | level: info 32 | path: ./logs 33 | BAIDU: 34 | APP_ID: XXXX 35 | API_KEY: XXXX 36 | SECRET_KEY: XXXX 37 | EMAIL: 38 | FROM: XXX 39 | HOST: XXX 40 | PORT: XXX 41 | PASSWORD: XXX 42 | JWT: 43 | JWT_CLIENTID: XXX 44 | JWT_BASE64SECRET: XXX 45 | HEFENG: 46 | KEY: XXX -------------------------------------------------------------------------------- /src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | logback 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 17 | 19 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | ${CONSOLE_LOG_PATTERN} 28 | 29 | 30 | 31 | 32 | 33 | 34 | INFO 35 | 36 | 37 | ${log.path}/${log.level}.%d{yyyy-MM-dd}.log 38 | 39 | 40 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 41 | 42 | 43 | 44 | 45 | 46 | ERROR 47 | 48 | 49 | ${log.path}/error.%d{yyyy-MM-dd}.log 50 | 51 | 52 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | --------------------------------------------------------------------------------