diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..d22ae3d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,174 @@ +name: Genius 多模块项目部署 [CI|CD]流 + +on: + push: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + + + - name: Checkout Auto Label + run: | + if [[ "${{ github.event.head_commit.message }}" == *""* ]]; then + echo "Commit message contains . Proceeding with the workflow." + else + echo "Commit message does not contain . Skipping the workflow." + exit 78 + fi + + - name: Get Commit Info + id: extract + run: | + commit_message="${{ github.event.head_commit.message }}" + echo "Commit Message: $commit_message" + + + env="" + module="" + module_type="" + version="" + skip="" + docker_env="" + run_port="" + + if [[ "$commit_message" =~ -e:([^\ ]*) ]]; then + env="${BASH_REMATCH[1]}" + fi + + if [[ "$commit_message" =~ -type:([^\ ]*) ]]; then + module_type="${BASH_REMATCH[1]}" + fi + + if [[ "$commit_message" =~ -m:([^\ ]*) ]]; then + module="${BASH_REMATCH[1]}" + fi + + if [[ "$commit_message" =~ -v:([^\ ]*) ]]; then + version="${BASH_REMATCH[1]}" + fi + + if [[ "$commit_message" =~ -skip:([^\ ]*) ]]; then + skip="${BASH_REMATCH[1]}" + fi + + if [[ "$commit_message" =~ -rp:([^\ ]*) ]]; then + run_port="${BASH_REMATCH[1]}" + fi + + + if [[ "$commit_message" =~ -de:\<([^>]+)\> ]]; then + + docker_env="${BASH_REMATCH[1]}" + fi + + echo "Environment: $env" + echo "Module: $module" + echo "Module_Type: $module_type" + echo "Version: $version" + echo "Skip: $skip" + echo "Run_Port: $run_port" + echo "Docker_Env: $docker_env" + + echo "ENV=$env" >> $GITHUB_ENV + echo "MODULE=$module" >> $GITHUB_ENV + echo "MODULE_TYPE=$module_type" >> $GITHUB_ENV + echo "VERSION=$version" >> $GITHUB_ENV + echo "SKIP=$skip" >> $GITHUB_ENV + echo "RUN_PORT=$run_port" >> $GITHUB_ENV + echo "DOCKER_ENV=$docker_env" >> $GITHUB_ENV + + - name: Set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + cache: maven + + - name: Build with Maven + if: ${{ env.SKIP != 'image'}} + env: + JASYPT_ALGO: ${{ secrets.JASYPT_ALGO }} + JASYPT_PWD: ${{ secrets.JASYPT_PWD }} + run: | + if [ "${{ env.MODULE_TYPE }}" != "single" ]; then + cd $MODULE + fi + echo "jasypt:" > src/main/resources/you-cant-see-that.yml + echo " encryptor:" >> src/main/resources/you-cant-see-that.yml + echo " algorithm: $JASYPT_ALGO" >> src/main/resources/you-cant-see-that.yml + echo " password: $JASYPT_PWD" >> src/main/resources/you-cant-see-that.yml + if [ "${{ env.MODULE_TYPE }}" != "single" ]; then + cd .. + fi + mvn package -Dmaven.test.skip=true + + - name: Build and Push Docker Images + if: ${{ env.SKIP != 'image'}} + env: + DOCKER_REPO: ${{ secrets.DOCKER_REPO }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PWD }} + run: | + echo "Module Name: $MODULE" + + if [ "${{ env.MODULE_TYPE }}" != "single" ]; then + cd $MODULE + fi + + mkdir docker + cp ./Dockerfile ./docker + cp ./target/*.jar ./docker + cd docker + docker build -t $DOCKER_REPO/$MODULE:$VERSION . + docker login -u $DOCKER_REPO -p $DOCKER_PASSWORD + docker push $DOCKER_REPO/$MODULE:$VERSION + + - name: Choose the Server Host + if: ${{ env.ENV != ''}} + run: | + pwd="" + host="" + port="" + if [ "${{ env.ENV }}" == "prod" ]; then + pwd="${{ secrets.PROD_PWD }}" + host="${{ secrets.PROD_ADDRESS }}" + port="${{ secrets.PROD_PORT }}" + elif [ "${{ env.ENV }}" == "test" ]; then + pwd="${{ secrets.TEST_PWD }}" + host="${{ secrets.TEST_ADDRESS }}" + port="${{ secrets.TEST_PORT }}" + else + echo "Invalid environment" + exit 1 + fi + echo "PWD=$pwd" >> $GITHUB_ENV + echo "HOST=$host" >> $GITHUB_ENV + echo "PORT=$port" >> $GITHUB_ENV + + - name: Connect Server + uses: appleboy/ssh-action@master + with: + # 同上述 + host: ${{ env.HOST }} + username: root + password: ${{ env.PWD }} + port: ${{ env.PORT }} + # ssh进入系统后执行什么样的操作。一般是关闭原有的服务在重启 + script: | + docker pull ${{ secrets.DOCKER_REPO }}/${{ env.MODULE }}:${{ env.VERSION }} + if [ "${{ env.RUN_PORT }}" != "" ]; then + stop_docker_name=$(docker ps --filter "expose=${{ env.RUN_PORT }}" --format "{{.Names}}") + if [ "$stop_docker_name" != "" ]; then + docker stop $stop_docker_name + fi + docker rm ${{ env.MODULE }}-${{ env.VERSION }} + + docker run -p ${{env.RUN_PORT}}:${{env.RUN_PORT}} --name ${{ env.MODULE }}-${{ env.VERSION }} ${{env.DOCKER_ENV}} -e JASYPT_PASSWORD=${{ secrets.JASYPT_PWD }} -d ${{ secrets.DOCKER_REPO }}/${{ env.MODULE }}:${{ env.VERSION }} + fi + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..212db0c --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ +application-dev.yml +/src/main/resources/bootstrap-dev.yml +/src/main/resources/you-cant-see-that.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d824ae0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,34 @@ +FROM adoptopenjdk:11-jre-hotspot +COPY *.jar /rvc-captcha.jar + + +ARG SERVER_PORT +ARG ACTIVE +ARG UNIQUE_ID +ARG JASYPT_PASSWORD + +ARG MYSQL_ADDR +ARG MYSQL_USERNAME +ARG MYSQL_PASSWORD + +ARG REDIS_ADDR +ARG REDIS_PORT +ARG REDIS_PWD + +ARG NACOS_SERVER_ADDR +ARG NACOS_SERVER_USER +ARG NACOS_SERVER_PASSWORD + +ARG MQ_ADDR +ARG MQ_PORT +ARG MQ_USERNAME +ARG MQ_PWD + +ENV SERVER_PORT=${SERVER_PORT} +ENV UNIQUE_ID=${UNIQUE_ID} +ENV JASYPT_PASSWORD = ${JASYPT_PASSWORD} +EXPOSE ${SERVER_PORT} + +ENTRYPOINT ["java","-jar","/rvc-captcha.jar"] + +# -e:test -type:single -m:rvc-captcha -v:1.0.2 -rp:8080 -de:<-e ACTIVE=test -e SERVER_PORT=8080> \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..ecc658f --- /dev/null +++ b/pom.xml @@ -0,0 +1,133 @@ + + + 4.0.0 + com.example + CaptchaMaster + 0.0.1-SNAPSHOT + CaptchaMaster + CaptchaMaster + + + org.springframework.boot + spring-boot-starter-parent + 2.4.1 + + + + + 11 + UTF-8 + UTF-8 + 2.3.9.RELEASE + 2020.0.3 + 3.0.1 + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.springframework.boot + spring-boot-starter-mail + + + com.github.ulisesbocchio + jasypt-spring-boot-starter + 3.0.3 + + + junit + junit + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + 2.2.5.RELEASE + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + 2.2.5.RELEASE + + + + org.springframework.cloud + spring-cloud-starter-bootstrap + + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + org.springframework.cloud + spring-cloud-starter-bootstrap + ${spring-cloud-start.version} + pom + import + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + JAR + + + + + repackage + + + false + + + + + + + + + src/main/resources + true + + + + + diff --git a/src/main/java/com/example/captchamaster/CaptchaMasterApplication.java b/src/main/java/com/example/captchamaster/CaptchaMasterApplication.java new file mode 100644 index 0000000..ee042e2 --- /dev/null +++ b/src/main/java/com/example/captchamaster/CaptchaMasterApplication.java @@ -0,0 +1,14 @@ +package com.example.captchamaster; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CaptchaMasterApplication { + + public static void main(String[] args) { + SpringApplication.run(CaptchaMasterApplication.class, args); + } + +} diff --git a/src/main/java/com/example/captchamaster/common/Result.java b/src/main/java/com/example/captchamaster/common/Result.java new file mode 100644 index 0000000..bdbbabe --- /dev/null +++ b/src/main/java/com/example/captchamaster/common/Result.java @@ -0,0 +1,82 @@ +package com.example.captchamaster.common; + +import com.example.captchamaster.pojo.StatusConstEnum; +import lombok.Data; + +import java.io.Serializable; + +import static com.example.captchamaster.pojo.StatusConstEnum.SUCCESS; +import static com.example.captchamaster.pojo.StatusConstEnum.SYSTEM_ERROR; + +/** + * @Description + * @Author welsir + * @Date 2023/11/23 19:36 + */ +@Data +public class Result implements Serializable { + + /** + * 返回状态 + */ + private Boolean flag; + + /** + * 返回码 + */ + private Integer code; + + /** + * 返回信息 + */ + private String message; + + /** + * 返回数据 + */ + private T data; + + public static Result success() { + return restResult(true, null, SUCCESS.getCode(), SUCCESS.getDesc()); + } + + public static Result success(T data) { + return restResult(true, data, SUCCESS.getCode(), SUCCESS.getDesc()); + } + + public static Result success(T data, String message) { + return restResult(true, data, SUCCESS.getCode(), message); + } + + + public static Result fail(StatusConstEnum statusConst) { + return restResult(false, null, statusConst.getCode(), statusConst.getDesc()); + } + + public static Result fail(String message) { + return restResult(false, message); + } + + + public static Result fail(Integer code, String message) { + return restResult(false, null, code, message); + } + + private static Result restResult(Boolean flag, String message) { + Result apiResult = new Result<>(); + apiResult.setFlag(flag); + apiResult.setCode(flag ? SUCCESS.getCode() : SYSTEM_ERROR.getCode()); + apiResult.setMessage(message); + return apiResult; + } + + private static Result restResult(Boolean flag, T data, Integer code, String message) { + Result apiResult = new Result<>(); + apiResult.setFlag(flag); + apiResult.setData(data); + apiResult.setCode(code); + apiResult.setMessage(message); + return apiResult; + } + +} diff --git a/src/main/java/com/example/captchamaster/common/builder/Graphics2DBuilder.java b/src/main/java/com/example/captchamaster/common/builder/Graphics2DBuilder.java new file mode 100644 index 0000000..9ec9b6f --- /dev/null +++ b/src/main/java/com/example/captchamaster/common/builder/Graphics2DBuilder.java @@ -0,0 +1,61 @@ +package com.example.captchamaster.common.builder; + +import com.example.captchamaster.service.CaptchaService; + +import java.awt.*; +import java.util.Random; + +/** + * @Date 2023/12/5 + * @Author xiaochun + */ +public class Graphics2DBuilder { + private final Graphics2D graphics2D; + + private String code; + + private int dotSize; + + public Graphics2DBuilder(Graphics2D graphics2D) { + this.graphics2D = graphics2D; + } + + public Graphics2DBuilder font(Color color, Font font){ + graphics2D.setColor(color); + graphics2D.setFont(font); + return this; + } + + public Graphics2DBuilder backgroundColor(Color color, int width, int height){ + graphics2D.setColor(color); + graphics2D.fillRect(0, 0, width, height); + return this; + } + + public Graphics2DBuilder code(String code){ + this.code = code; + return this; + } + + public Graphics2DBuilder dot(int size){ + this.dotSize = size; + return this; + } + + public Graphics2DBuilder draw(int width, int height){ + graphics2D.drawString(code, 25, 35); + Random random = new Random(); + for (int i = 0; i < this.dotSize; i++) { + int dotX = random.nextInt(width); + int dotY = random.nextInt(height); + graphics2D.setColor(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256))); + graphics2D.fillRect(dotX, dotY, 2, 2); + } + return this; + } + + public boolean done(){ + graphics2D.dispose(); + return true; + } +} diff --git a/src/main/java/com/example/captchamaster/common/captcha/CaptchaHandler.java b/src/main/java/com/example/captchamaster/common/captcha/CaptchaHandler.java new file mode 100644 index 0000000..9f6c99b --- /dev/null +++ b/src/main/java/com/example/captchamaster/common/captcha/CaptchaHandler.java @@ -0,0 +1,5 @@ +package com.example.captchamaster.common.captcha; + +public interface CaptchaHandler { + Res CaptchaCode(Param param); +} diff --git a/src/main/java/com/example/captchamaster/common/captcha/CommonCaptchaHandler.java b/src/main/java/com/example/captchamaster/common/captcha/CommonCaptchaHandler.java new file mode 100644 index 0000000..46ed12c --- /dev/null +++ b/src/main/java/com/example/captchamaster/common/captcha/CommonCaptchaHandler.java @@ -0,0 +1,5 @@ +package com.example.captchamaster.common.captcha; + +abstract public class CommonCaptchaHandler implements CaptchaHandler { + protected int codeLength; +} diff --git a/src/main/java/com/example/captchamaster/common/captcha/EmailCaptcha.java b/src/main/java/com/example/captchamaster/common/captcha/EmailCaptcha.java new file mode 100644 index 0000000..2526108 --- /dev/null +++ b/src/main/java/com/example/captchamaster/common/captcha/EmailCaptcha.java @@ -0,0 +1,30 @@ +package com.example.captchamaster.common.captcha; + + +import com.example.captchamaster.util.CodeUtil; +import com.example.captchamaster.util.EmailUtil; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; + +public class EmailCaptcha extends CommonCaptchaHandler, String>{ + @Resource + private EmailUtil emailUtil; + + public EmailCaptcha() { + this(6); + } + + public EmailCaptcha(int codeLength) { + this.codeLength = codeLength; + } + + @Override + public Map CaptchaCode(String email) { + String code = CodeUtil.code(this.codeLength); + emailUtil.sendCode(email, code); + return Map.of("email", email, "code", code); + } +} diff --git a/src/main/java/com/example/captchamaster/common/captcha/ImageCaptcha.java b/src/main/java/com/example/captchamaster/common/captcha/ImageCaptcha.java new file mode 100644 index 0000000..3add444 --- /dev/null +++ b/src/main/java/com/example/captchamaster/common/captcha/ImageCaptcha.java @@ -0,0 +1,26 @@ +package com.example.captchamaster.common.captcha; + +import com.example.captchamaster.util.CodeUtil; +import com.example.captchamaster.util.ImageUtil; + +import javax.annotation.Resource; +import java.util.Map; + +public class ImageCaptcha extends CommonCaptchaHandler, String>{ + @Resource + ImageUtil imageUtil; + + public ImageCaptcha() { + this.codeLength = 5; + } + + public ImageCaptcha(int codeLength){ + this.codeLength = codeLength; + } + + @Override + public Map CaptchaCode(String msg) { + String code = CodeUtil.code(this.codeLength); + return Map.of("base64",imageUtil.CodeToBase64(code), "code",code); + } +} diff --git a/src/main/java/com/example/captchamaster/config/CaptchaConfig.java b/src/main/java/com/example/captchamaster/config/CaptchaConfig.java new file mode 100644 index 0000000..c590582 --- /dev/null +++ b/src/main/java/com/example/captchamaster/config/CaptchaConfig.java @@ -0,0 +1,28 @@ +package com.example.captchamaster.config; + +import com.example.captchamaster.common.captcha.CommonCaptchaHandler; +import com.example.captchamaster.common.captcha.EmailCaptcha; +import com.example.captchamaster.common.captcha.ImageCaptcha; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Map; + +@Configuration +public class CaptchaConfig { + public static String ENCODE = "1234567890abcdefghijklmnopqrstuvwxwzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + @Value("${captcha.mail.code-length}") + private int codeLength; + + @Bean + public CommonCaptchaHandler, String> emailCaptcha(){ + return new EmailCaptcha(codeLength); + } + + @Bean + public CommonCaptchaHandler, String> imageCaptcha(){ + return new ImageCaptcha(codeLength); + } +} diff --git a/src/main/java/com/example/captchamaster/config/HtmlContentConfig.java b/src/main/java/com/example/captchamaster/config/HtmlContentConfig.java new file mode 100644 index 0000000..7e196a4 --- /dev/null +++ b/src/main/java/com/example/captchamaster/config/HtmlContentConfig.java @@ -0,0 +1,21 @@ +package com.example.captchamaster.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; +import org.springframework.util.FileCopyUtils; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +@Configuration +public class HtmlContentConfig { + + @Bean + public String htmlContent() throws IOException { + ClassPathResource resource = new ClassPathResource("email-template.html"); + byte[] fileData = FileCopyUtils.copyToByteArray(resource.getInputStream()); + return new String(fileData, StandardCharsets.UTF_8); + } + +} diff --git a/src/main/java/com/example/captchamaster/controller/CaptchaController.java b/src/main/java/com/example/captchamaster/controller/CaptchaController.java new file mode 100644 index 0000000..0126291 --- /dev/null +++ b/src/main/java/com/example/captchamaster/controller/CaptchaController.java @@ -0,0 +1,31 @@ +package com.example.captchamaster.controller; + +import com.example.captchamaster.common.Result; +import com.example.captchamaster.service.CaptchaService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * @Date 2023/12/4 + * @Author xiaochun + */ +@RestController +@RequestMapping("/captcha") +public class CaptchaController { + @Resource + CaptchaService captchaService; + + @GetMapping("/email") + public Result> email(String to){ + return Result.success(captchaService.sendEmailCode(to)); + } + + @GetMapping("/image") + public Result> image(){ + return Result.success(captchaService.imageCode()); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/captchamaster/pojo/StatusConstEnum.java b/src/main/java/com/example/captchamaster/pojo/StatusConstEnum.java new file mode 100644 index 0000000..fe24139 --- /dev/null +++ b/src/main/java/com/example/captchamaster/pojo/StatusConstEnum.java @@ -0,0 +1,37 @@ +package com.example.captchamaster.pojo; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @Description + * @Author welsir + * @Date 2023/11/24 20:43 + */ +@Getter +@AllArgsConstructor +public enum StatusConstEnum { + /** + * 成功 + */ + SUCCESS(200, "成功"), + + /** + * 系统异常 + */ + SYSTEM_ERROR(500, "系统异常"), + + SEND_EMIAL_CODE_FAILED(418, "验证码发送失败"), + + ; + + /** + * 状态码 + */ + private final Integer code; + + /** + * 描述 + */ + private final String desc; +} diff --git a/src/main/java/com/example/captchamaster/service/CaptchaService.java b/src/main/java/com/example/captchamaster/service/CaptchaService.java new file mode 100644 index 0000000..d31eb3c --- /dev/null +++ b/src/main/java/com/example/captchamaster/service/CaptchaService.java @@ -0,0 +1,27 @@ +package com.example.captchamaster.service; + +import com.example.captchamaster.common.captcha.CommonCaptchaHandler; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * @Date 2023/12/4 + * @Author xiaochun + */ +@Component +public class CaptchaService { + @Resource + private CommonCaptchaHandler, String> emailCaptcha; + + @Resource + private CommonCaptchaHandler, String> imageCaptcha; + public Map sendEmailCode(String to){ + return emailCaptcha.CaptchaCode(to); + } + + public Map imageCode(){ + return imageCaptcha.CaptchaCode(null); + } +} diff --git a/src/main/java/com/example/captchamaster/util/CodeUtil.java b/src/main/java/com/example/captchamaster/util/CodeUtil.java new file mode 100644 index 0000000..4f4ddab --- /dev/null +++ b/src/main/java/com/example/captchamaster/util/CodeUtil.java @@ -0,0 +1,20 @@ +package com.example.captchamaster.util; + + +import com.example.captchamaster.config.CaptchaConfig; + +import java.util.Random; + +public class CodeUtil { + + public static String code(){ + return code(6); + } + + public static String code(int codeLength){ + Random random = new Random(System.nanoTime()); + StringBuilder code = new StringBuilder(); + for (int i = 0; i < codeLength; i++) code.append(CaptchaConfig.ENCODE.charAt(random.nextInt(58))); + return code.toString(); + } +} diff --git a/src/main/java/com/example/captchamaster/util/EmailUtil.java b/src/main/java/com/example/captchamaster/util/EmailUtil.java new file mode 100644 index 0000000..fac56bc --- /dev/null +++ b/src/main/java/com/example/captchamaster/util/EmailUtil.java @@ -0,0 +1,41 @@ +package com.example.captchamaster.util; + + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; + +@Component +public class EmailUtil { + @Value("${spring.mail.username}") + private String from; + @Resource + private String htmlContent; // HTML模板内容 + @Resource + private JavaMailSender mailSender; + + public EmailUtil() { + } + + public void sendCode(String to, String code) { + MimeMessage message = mailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(message, "utf-8"); + + try { + helper.setTo(to); + helper.setFrom(from); + // 邮件主题 + String subject = "这是一条验证码"; + helper.setSubject(subject); + helper.setText(htmlContent.replace("CODE", code), true); + mailSender.send(message); + } catch (MessagingException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/example/captchamaster/util/ImageUtil.java b/src/main/java/com/example/captchamaster/util/ImageUtil.java new file mode 100644 index 0000000..1ac5fdc --- /dev/null +++ b/src/main/java/com/example/captchamaster/util/ImageUtil.java @@ -0,0 +1,51 @@ +package com.example.captchamaster.util; + +import com.example.captchamaster.common.builder.Graphics2DBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.Base64; +import java.util.Random; + +@Component +public class ImageUtil { + @Value("${captcha.image-code.width}") + private int width; + @Value("${captcha.image-code.height}") + private int height; + @Value("${captcha.image-code.dot-size}") + private int dotsSize; + private final Random random = new Random(); + public String CodeToBase64(String code){ + BufferedImage captchaImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + Graphics2DBuilder graphics2DBuilder = new Graphics2DBuilder(captchaImage.createGraphics()); + graphics2DBuilder + .code(code) + .backgroundColor(randColor(), width, height) + .font(randColor(), randFont()) + .dot(dotsSize) + .draw(width, height) + .done(); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try { + ImageIO.write(captchaImage, "png", outputStream); + } catch (IOException e) { + throw new RuntimeException(e); + } + byte[] imageBytes = outputStream.toByteArray(); + return Base64.getEncoder().encodeToString(imageBytes); + } + private Font randFont(){ + return new Font("Arial", Font.ITALIC, 40); + } + private Color randColor(){ + return new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)); + } +} diff --git a/src/main/resources/bootstrap-prod.yml b/src/main/resources/bootstrap-prod.yml new file mode 100644 index 0000000..da0ec3f --- /dev/null +++ b/src/main/resources/bootstrap-prod.yml @@ -0,0 +1,24 @@ +spring: + application: + name: tml-captcha-service + cloud: + nacos: + server-addr: ${NACOS_SERVER_ADDR:ENC(mZ6KsI+EkqODZAH2qdKUJzlo66asDZxKegO5bkjb3hwJb8y6FkFOLA==)} + username: ${NACOS_SERVER_USER:ENC(fjV9WIPRx0giRHfPe+sQ4RdkUyvAY3sp)} + password: ${NACOS_SERVER_PASSWORD:ENC(NZYKzLvLPo+HLsfOxoPkIA1XLClwp2VI1p4frx2IrPXvI0rm6egfmQ==)} + discovery: + namespace: b21e6a4b-33d1-44c3-9b24-8a682c897292 + ip: ${SERVER_ADDR:ENC(k8vJSnZr6caJGxQ1KPjdbKYkVJrBUeSWSAK0ry8TfBk=)} + mail: + host: ${EMIAL_HOST:ENC(qMKUwBybaAKewuGZCDYjQw6tCfRVAO5aIQUolS8L06U=)} + port: ${EMAIL_PORT:ENC(7RRjEe4cBjcETAkyZ6TBh5zwIw6KrEaz)} + username: ${EMAIL_USERNAME:ENC(Ndpes2aPfHdQQLG2Ds47yIxEh5/YB2ywTbf7UZ8Re7JgCTjwemDMQw==)} + password: ${EMAIL_PASSWORD:ENC(IFKjNrj7WUsXTiTldZ8TDgHxBxgkYHXBD5RrrjZ2SlGFXMCaObgqgA==)} + test-connection: false +captcha: + mail: + code-length: 6 + image-code: + width: 180 + height: 40 + dot-size: 50 \ No newline at end of file diff --git a/src/main/resources/bootstrap-test.yml b/src/main/resources/bootstrap-test.yml new file mode 100644 index 0000000..ab0044e --- /dev/null +++ b/src/main/resources/bootstrap-test.yml @@ -0,0 +1,25 @@ +spring: + application: + name: tml-captcha-service + cloud: + nacos: + server-addr: ${NACOS_SERVER_ADDR:ENC(mZ6KsI+EkqODZAH2qdKUJzlo66asDZxKegO5bkjb3hwJb8y6FkFOLA==)} + username: ${NACOS_SERVER_USER:ENC(fjV9WIPRx0giRHfPe+sQ4RdkUyvAY3sp)} + password: ${NACOS_SERVER_PASSWORD:ENC(NZYKzLvLPo+HLsfOxoPkIA1XLClwp2VI1p4frx2IrPXvI0rm6egfmQ==)} + discovery: + namespace: b21e6a4b-33d1-44c3-9b24-8a682c897292 + ip: ${SERVER_ADDR:ENC(k8vJSnZr6caJGxQ1KPjdbKYkVJrBUeSWSAK0ry8TfBk=)} + mail: + host: ${EMIAL_HOST:ENC(qMKUwBybaAKewuGZCDYjQw6tCfRVAO5aIQUolS8L06U=)} + port: ${EMAIL_PORT:ENC(7RRjEe4cBjcETAkyZ6TBh5zwIw6KrEaz)} + username: ${EMAIL_USERNAME:ENC(Ndpes2aPfHdQQLG2Ds47yIxEh5/YB2ywTbf7UZ8Re7JgCTjwemDMQw==)} + password: ${EMAIL_PASSWORD:ENC(IFKjNrj7WUsXTiTldZ8TDgHxBxgkYHXBD5RrrjZ2SlGFXMCaObgqgA==)} + test-connection: false + +captcha: + mail: + code-length: 6 + image-code: + width: 180 + height: 40 + dot-size: 50 \ No newline at end of file diff --git a/src/main/resources/bootstrap.yml b/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..4976026 --- /dev/null +++ b/src/main/resources/bootstrap.yml @@ -0,0 +1,8 @@ +server: + port: ${SERVER_PORT:9050} + +spring: + config: + import: classpath:you-cant-see-that.yml + profiles: + active: ${ACTIVE:dev} \ No newline at end of file diff --git a/src/main/resources/email-template.html b/src/main/resources/email-template.html new file mode 100644 index 0000000..6b511eb --- /dev/null +++ b/src/main/resources/email-template.html @@ -0,0 +1,108 @@ + + + + + Title + + + +
+
+ +
+ +
+ +
+

嗨,您好:

+
+ +
+

+ 此处是您所需要的邮箱 令牌验证码: +

+
+ +
+

CODE

+
+ +
+

不是您?

+

您会收到这封电子邮件,是由于有人试图操作您的 Mixi 账户,且提供了正确的账户名称。 +

+

如果不是您,可以不用理会这封邮件。

+

此电子邮件包含一个权限代码,切勿与任何人分享此代码

+
+ +
+

祝您愉快,

+

TML 团队

+
+
+
+ + \ No newline at end of file diff --git a/src/test/java/com/example/captchamaster/CaptchaMasterApplicationTests.java b/src/test/java/com/example/captchamaster/CaptchaMasterApplicationTests.java new file mode 100644 index 0000000..3a88584 --- /dev/null +++ b/src/test/java/com/example/captchamaster/CaptchaMasterApplicationTests.java @@ -0,0 +1,13 @@ +package com.example.captchamaster; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class CaptchaMasterApplicationTests { + + @Test + void contextLoads() { + } + +}