12.支付宝支付、邮件发送
支付宝支付
前置准备
支付宝开放平台登录
利用支付宝秘钥工具,通过私钥生成公钥
再通过应用公钥去网站 生成支付宝公钥
1.加入支付宝支付依赖
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-easysdk</artifactId>
<version>2.0.2</version>
</dependency>
2.在配置文件中配置支付宝相关配置
alipay:
appId: #换成你自己的APPID
privateKey: #换成你自己的私钥
publicKey: #支付宝公钥 通过公钥生成的支付宝公钥
gateway: #支付网关配置,这一项是写死的,正式环境是openapi.alipay.com
returnUrl: #支付成功之后的回调页面,只是一个友好页面。主要换成你自己映射的临时域名
notifyUrl: #支付成功的接口回调,我们还没写,先空着
3.初始化支付宝相关配置
package com.wang.config;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
/**
* @Classname AlipayConfig
* @Description 初始化支付宝的相关配置
* @Date 2024/10/18 13:51
* @Created by pc
*/
@Component
public class AlipayConfig implements ApplicationRunner {
@Value("${alipay.appId}")
private String appId;
@Value("${alipay.privateKey}")
private String privateKey;
@Value("${alipay.publicKey}")
private String publicKey;
@Value("${alipay.gateway}")
private String gateway;
@Value("${alipay.returnUrl}")
private String returnUrl;
@Value("${alipay.notifyUrl}")
private String notifyUrl;
@Override
public void run(ApplicationArguments args) throws Exception {
Factory.setOptions(getOptions());
System.out.println("************支付宝SDK初始化完成********");
}
public Config getOptions(){
Config config = new Config();
config.protocol="https"; // 协议
config.gatewayHost=this.gateway;// 网关
config.signType="RSA2";// 加密算法类型
config.appId=this.appId; // appId
config.merchantPrivateKey = this.privateKey;// 私钥
config.alipayPublicKey = this.publicKey;// 支付宝公钥
config.notifyUrl = this.notifyUrl; // 支付宝回调接口
return config;
}
}
4.写一个根据时间戳生成订单的工具类
package com.wang.utils;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
/**
* @Classname OrderNo
* @Description 根据时间戳生成一个订单号
* @Date 2024/10/18 14:09
* @Created by pc
*/
public class OrderNo {
/**
* 根据时间戳生成订单号
* */
public static String getOrderNo () {
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
LocalDateTime localDateTime = Instant.ofEpochMilli(System.currentTimeMillis()).atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
return df.format(localDateTime);
}
}
5.支付时相关参数
package com.wang.bo;
import lombok.*;
import java.math.BigDecimal;
/**
* @Classname PayBo
* @Description 发起支付的参数 -- 支付的项目 金额
* @Date 2024/10/18 14:04
* @Created by pc
*/
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class PayBo {
private String subject;
private BigDecimal total = BigDecimal.ZERO;
}
6.支付宝支付的service
package com.wang.service;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.wang.bo.PayBo;
import com.wang.utils.OrderNo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
/**
* @Classname PayService
* @Description TODO
* @Date 2024/10/18 14:03
* @Created by pc
*/
@Service
public class PayService {
@Value("${alipay.returnUrl}")
private String returnUrl;
/*
* 下单支付
* */
public Object pay(PayBo bo) throws Exception {
// 生成订单号
String orderNo = OrderNo.getOrderNo();
//调用支付宝的SDK中支付方法 最终由支付宝生一个支付的页面 我们去这个页面付钱 AlipayTradePagePayResponse
AlipayTradePagePayResponse response = Factory.Payment
// 选择网页平台支付
.Page()
// 调用支付方法 传递参数
// 产品名称 订单号 支付总金额 调用的回调页面
.pay(bo.getSubject(),orderNo, bo.getTotal().toString(), returnUrl);
// 生成一个支付页面片段
return response.body;
}
}
7.支付的Controller
package com.wang.controller.api;
import com.wang.bo.PayBo;
import com.wang.service.PayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* @Classname ApiPayController
* @Description TODO
* @Date 2024/10/18 14:14
* @Created by pc
*/
@RestController
@Slf4j
@RequestMapping("/api/pay")
public class ApiPayController {
@Resource
private PayService payService;
@PostMapping(value = "/confirm",produces = {"text/html;charset=utf-8"})
public Object pay(PayBo payBo) throws Exception {
return payService.pay(payBo);
}
@PostMapping("/notify")
// 支付成功之后 支付宝会调用这个回调接口 返回一些参数 这些参数会通过请求封装过来 我们可以在接口中获取
public void notify(HttpServletRequest request){
Map<String, String[]> map = request.getParameterMap();
map.forEach((k,v)->{
System.out.println("----------------"+k+"------------------");
for (String s : v) {
System.out.println(s);
}
});
}
}
8.支付的页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<form action="/api/pay/confirm" method="post">
商品名称: <input type="text" name="subject"> <br>
价格: <input type="text" name="total"> <br>
<input type="submit" value="确认支付">
</form>
</div>
</body>
</html>
<template>
<el-form
ref="ruleFormRef"
style="max-width: 600px"
:model="ruleForm"
status-icon
label-width="auto"
class="demo-ruleForm"
>
<el-form-item label="商品名称" prop="pass">
<el-text class="mx-1" size="large" v-model="ruleForm.subject">{{ ruleForm.subject }}</el-text>
</el-form-item>
<el-form-item label="金额" prop="checkPass">
<el-text class="mx-1" size="large" v-model="ruleForm.total">{{ ruleForm.total }}</el-text>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="confirm">
Submit
</el-button>
</el-form-item>
</el-form>
<!-- 在页面中有一个可以提供渲染的元素 -->
<div ref="alipayWap" v-html="alipay" />
</template>
<script setup>
import {ref,nextTick,getCurrentInstance} from "vue";
import {useRoute} from "vue-router";
import {pay} from "../api/payApi.js";
const {proxy} = getCurrentInstance()
const route = useRoute();
const ruleForm = ref({
subject: route.query.subject,
total :route.query.total
})
const alipay = ref()
async function confirm(){
let {data:data} = await pay(ruleForm.value)
console.log(data)
alipay.value = data
// 将数据渲染到元素内,通过触发表单的 提交事件,可以调起支付接口
nextTick(() => {
// 提交支付表单
proxy.$refs.alipayWap.children[0].submit();
setTimeout(() => {
// this.toPayFlag = false;
}, 500);
});
}
</script>
<style scoped>
</style>
Mail邮件
一.邮件发送概述
1.概述
在Spring框架中提供了一个JavaMailSender接口,可以实现发送邮件功能。
而在Spring Boot中提供了一个对应的spring-boot-starter-mail依赖,添加该依赖后,Spring Boot将创建一个默认的JavaMailSender,该sender可以通过spring.mail命名空间下的配置项进一步自定义。
2.发送邮件的场景
(1)用户通过邮件注册激活;
(2)通过邮件找回密码;
(3)通过邮件发送系统情况;
(4)通过邮件发送报表信息等。
3.常用邮箱系统供应商
126邮箱SMTP服务器地址:smtp.126.com,端口号:465或者994
163邮箱SMTP服务器地址:smtp.163.com,端口号:465或者994
qq邮箱SMTP服务器地址:smtp.qq.com,端口号:465或587
yeah邮箱SMTP服务器地址:smtp.yeah.net,端口号:465或者994
4.QQ邮箱开启SMTP功能
为了保障用户邮箱的安全,QQ邮箱设置了POP3/SMTP/IMAP的开关。系统默认情况下相关设置是“关闭”状态的,在用户需要这些功能时请先“开启”,才可以用客户端软件收发邮件。
QQ邮箱开启SMTP功能步骤
默认情况下,SMTP服务器功能没有开启,所以需要在“设置”-->"账号"-->"POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务"中对SMTP进行开启。
开启成功后,会有一个授权码,这个授权码就是我们进行邮件发送时的邮箱密码,可以把它记住,不记也可以。因为这个授权码可以多次生成,只要用的时候发一次短信验证码,就可以得到一个新的授权码了。
1.引入依赖
<dependencies>
<!-- web支持: 1、web mvc; 2、restful; 3、jackjson支持; 4、aop ........ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!--简化bean代码-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
2.配置文件
server:
port: 8080
servlet:
context-path: /
spring:
freemarker:
template-loader-path: classpath:/templates/
suffix: .ftl
cache: false
charset: UTF-8
check-template-location: true
context-type: text/html
#邮箱配置
mail:
host: smtp.qq.com
from: 446470238@qq.com
username: 446470238@qq.com
password: djnxxmyhuzkwcbbb
protocol: smtp
default-encoding: UTF-8
properties:
mail:
smtp:
ssl:
enable: true
auth: true
starttls:
enable: true
required: true
5.发送邮件接口
package com.wang.service;
import javax.mail.MessagingException;
public interface MailService {
/**
* 发送文本邮件
*
* @param to 收件人
* @param subject 主题
* @param content 内容
*/
void sendSimpleMail(String to, String subject, String content);
/**
* 发送HTML邮件
*
* @param to 收件人
* @param subject 主题
* @param content 内容
*/
void sendHtmlMail(String to, String subject, String content);
/**
* 发送带附件的邮件
*
* @param to 收件人
* @param subject 主题
* @param content 内容
* @param filePath 附件
*/
void sendAttachmentsMail(String to, String subject, String content, String filePath);
/**
* 发送模板文件
*
* @param to 收件人
* @param subject 主题
* @param fileName 邮件模板文件名称
* @param model 邮件数据载体
*/
void sendModelMail(String to, String subject, String fileName, Object model) throws MessagingException;
}
6.接口实现
package com.wang.service.impl;
import com.wang.service.MailService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.Objects;
/**
* @Classname MailServiceImpl
* @Description TODO
* @Date 2025/2/19 13:52
* @Created by pc
*/
@Service
@Slf4j
public class MailServiceImpl implements MailService {
@Resource
private JavaMailSender mailSender;
@Value("${spring.mail.from}")
private String from;
@Resource
private Configuration configuration;
@Override
public void sendSimpleMail(String to, String subject, String content) {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(from);
message.setTo(to);
message.setSubject(subject);
message.setText(content);
mailSender.send(message);
}
@Override
public void sendHtmlMail(String to, String subject, String content) {
MimeMessage message = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content,true);
mailSender.send(message);
log.info("邮件已发送");
} catch (MessagingException e) {
// throw new RuntimeException(e);
e.printStackTrace();
log.error("发送失败",e);
}
}
@Override
public void sendAttachmentsMail(String to, String subject, String content, String filePath) {
MimeMessage message = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content,true);
// 带附件
ClassPathResource resource = new ClassPathResource(filePath);
FileSystemResource file = new FileSystemResource(resource.getFile());
helper.addAttachment(Objects.requireNonNull(file.getFilename()),file);
mailSender.send(message);
log.info("邮件已发送");
} catch (Exception e) {
e.printStackTrace();
log.error("发送失败",e);
}
}
@Override
public void sendModelMail(String to, String subject, String fileName, Object model) throws MessagingException {
MimeMessage message = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
Template template = configuration.getTemplate(fileName);
String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
helper.setText(html,true);
mailSender.send(message);log.info("邮件已发送");
} catch (Exception e) {
e.printStackTrace();
log.error("发送失败",e);
}
}
}
7.控制器
package com.wang.controller;
import com.wang.entity.Employee;
import com.wang.service.MailService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.mail.MessagingException;
/**
* @Classname MailController
* @Description TODO
* @Date 2025/2/19 13:56
* @Created by pc
*/
@RestController
@Slf4j
public class MailController {
@Resource
private MailService mailService;
@GetMapping("/simple")
public String sendSimpleMail() {
mailService.sendSimpleMail("446470238@qq.com", "你打开看看", "什么也没有");
return "success";
}
@GetMapping("/html")
public String sendHtmlMail() {
mailService.sendHtmlMail("446470238@qq.com", "你打开看看", "<h1>邮件主题</h1><br/><p><font color='red'>什么也没有</font></p>");
return "success";
}
@GetMapping("/attachment")
public String sendAttachmentMail() {
mailService.sendAttachmentsMail("446470238@qq.com", "主题:带附件的邮件", "有附件的邮件,不要错过哦...", "static/lock.png");
return "success";
}
@PostMapping("/model")
public String sendModelMail(@RequestBody Employee employee) throws MessagingException {
mailService.sendModelMail("446470238@qq.com", "主题:新员工入职欢迎邮件--模板邮件", "mail.ftl", employee);
return "success";
}
}
8.模版文件
<p>${username}--你好,欢迎加入XXX大家庭!您的入职信息如下:</p>
<table border="1" cellspacing="0">
<tr><td><strong style="color: #F00">工号</strong></td><td>${id}</td></tr>
<tr><td><strong style="color: #F00">合同期限</strong></td><td>${contractTerm}年</td></tr>
<tr><td><strong style="color: #F00">员工薪资</strong></td><td>${salary}/月(美元)</td></tr>
<tr><td><strong style="color: #F00">合同起始日期</strong></td><td>${beginContact?string("yyyy-MM-dd")}</td></tr>
<tr><td><strong style="color: #F00">合同截至日期</strong></td><td>${endContact?string("yyyy-MM-dd")}</td></tr>
<tr><td><strong style="color: #F00">所属部门</strong></td><td>${departmentName}</td></tr>
<tr><td><strong style="color: #F00">职位</strong></td><td>${posName}</td></tr>
</table>
<p><strong style="color: #F00; font-size: 24px;">希望在未来的日子里,携手共进!</strong></p>
9.实体类
package com.wang.entity;
import lombok.Data;
import java.util.Date;
@Data
public class Employee {
private Long id;
private String username;
private Integer contractTerm;
private Double salary;
private Date beginContact;
private Date endContact;
private String departmentName;
private String posName;
}
二.邮件注册激活功能
1.引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--MySQL-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--Druid数据库连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--邮件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
2.配置文件
spring:
datasource:
url: jdbc:mysql://localhost:3306/db66?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: wang
driverClassName: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
#页面模板配置
thymeleaf:
prefix: classpath:/templates/
suffix: .html
mail:
host: smtp.qq.com
from: 446470238@qq.com
username: 446470238@qq.com
password: djnxxmyhuzkwcbbb
protocol: smtp
default-encoding: UTF-8
properties:
mail:
smtp:
ssl:
enable: true
auth: true
starttls:
enable: true
required: true
server:
tomcat:
uri-encoding: UTF-8
3.实体类
@Data
public class User implements Serializable {
private Integer id;
private String username;
private String password;
@Column(name = "usermail")
private String userMail;
/**
* 状态:0代表未激活,1代表激活
*/
private Integer status;
/**
* 用UUID生成一段数字,发送到用户邮箱,当用户点击链接时,再做一个校验,
* 如果用户传来的code跟我们发送的code一致,则更改状态为"1"来激活用户。
*/
private String code;
}
4.工具类
public class UUIDUtil {
public static String getUUID(){
return UUID.randomUUID().toString().replaceAll("-","");
}
public static void main(String[] args) {
System.out.println(UUID.randomUUID().toString().replaceAll("-",""));
}
}
5.mapper接口
User findUserByCode(String code);
User findByUsernameAndPassword(String username, String password);
public interface UserService {
// 注册
void reg(User user);
// 根据激活码查找用户
User checkedCode(String code);
// 激活 修改用户状态
void updateUserStatus(User user);
// 登录
User login(User user);
}
发送短信
本文来自博客园,作者:icui4cu,转载请注明原文链接:https://www.cnblogs.com/icui4cu/p/18910116