https://blog.csdn.net/zhaihuilin0986/article/details/78530657
一.在 pox.xml 中 加入 <!--email依賴--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency>
二。創(chuàng)建一個(gè)用戶實(shí)體
/**
* .
*/
@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor
public class Member implements Serializable {
? ? @Id
? ? @GenericGenerator(name = "sys_uid",strategy = "com.zhaihuilin.util.KeyGeneratorUtils",parameters = {
? ? ? ? ? ? @Parameter(name = "k",value = "M")
? ? })
? ? @GeneratedValue(generator = "sys_uid")
? ? private? String? id;
? ? //用戶名
? ? @NonNull
? ? private? String? username;
? ? //昵稱
? ? private? String? nickname;
? ? @NonNull
? ? //密碼
? ? private? String? password;
? ? @NonNull
? ? //郵箱
? ? private? String? email;
? ? //電話號碼
? ? private? String? smscode;
? ? //用戶狀態(tài)
? ? private? String? state;
? ? public Member( String username, String nickname, String password, String email, String smscode, String state) {
? ? ? ? this.username = username;
? ? ? ? this.nickname = nickname;
? ? ? ? this.password = password;
? ? ? ? this.email = email;
? ? ? ? this.smscode = smscode;
? ? ? ? this.state = state;
? ? }
? ? public Member(String username, String nickname, String password, String email, String state) {
? ? ? ? this.username = username;
? ? ? ? this.nickname = nickname;
? ? ? ? this.password = password;
? ? ? ? this.email = email;
? ? ? ? this.state = state;
? ? }
}
三.配置文件?
1.application-dev.yml
spring:
? jpa:
? ? show-sql: true
? ? hibernate:
? ? ? ddl-auto: update
? datasource:
? ? url: jdbc:mysql://127.0.0.1:3306/sms?characterEncoding=UTF-8
? ? username: root
? ? password: root
? ? driver-class-name: com.mysql.jdbc.Driver
? ? minIdle: 2
? ? maxAction: 20
? ? maxWaitMillis: 8000
? cache:
? ? type: redis
? redis:
? ? database: 2
? ? host: 127.0.0.1
? ? port: 6379
? ? timeout: 20000
? ? pool:
? ? ? max-active: 8
? ? ? min-idle: 0
? ? ? max-idle: 8
? ? ? max-wait: -1
2.application-.yml
server:
? tomcat:
? ? uri-encoding: utf-8
? port: 8087
? context-path: /
spring:
? profiles:
? ? active: dev
? mail:
? ? host: smtp.163.com
? ? username: 郵箱?
? ? password: 郵箱的登錄密碼
? ? port: 25
? ? default-encoding: UTF-8
? ? protocol: smtp
? ? properties:
? ? ? mail:
? ? ? ? smth:
? ? ? ? ? auth: true
? ? ? ? ? starttls:
? ? ? ? ? ? enable: true
? ? ? ? ? ? required: true
四。編寫相應(yīng)的 dao ?service ?[此處省略]
五。編寫工具類
//實(shí)體類主鍵生成策略
public class KeyGeneratorUtils extends AbstractUUIDGenerator implements Configurable {
? ? public String k;
? ? @Override
? ? public void configure(Type type, Properties properties, ServiceRegistry serviceRegistry) throws MappingException {
? ? ? ? k = properties.getProperty("k");
? ? }
? ? @Override
? ? public Serializable generate(SessionImplementor sessionImplementor, Object o) throws HibernateException {
? ? ? ? SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
? ? ? ? return k + simpleDateFormat.format(new Date());
? ? }
}
//時(shí)間處理類
public class NormalTools {
? ? public static String getFileType(String fileName) {
? ? ? ? if(fileName!=null && fileName.indexOf(".")>=0) {
? ? ? ? ? ? return fileName.substring(fileName.lastIndexOf("."), fileName.length());
? ? ? ? }
? ? ? ? return "";
? ? }
? ? /**
? ? * 判斷文件是否為圖片文件
? ? * @param fileName
? ? * @return
? ? */
? ? public static Boolean isImageFile(String fileName) {
? ? ? ? String [] img_type = new String[]{".jpg", ".jpeg", ".png", ".gif", ".bmp"};
? ? ? ? if(fileName==null) {return false;}
? ? ? ? fileName = fileName.toLowerCase();
? ? ? ? for(String type : img_type) {
? ? ? ? ? ? if(fileName.endsWith(type)) {return true;}
? ? ? ? }
? ? ? ? return false;
? ? }
? ? public static String curDate(String pattern) {
? ? ? ? SimpleDateFormat sdf = new SimpleDateFormat(pattern);
? ? ? ? return sdf.format(new Date());
? ? }
? ? public static String curDate() {
? ? ? ? return curDate("yyyy-MM-dd HH:mm:ss");
? ? }
}
//隨機(jī)生成6位數(shù)
public class RandomTools {
? ? /** 隨機(jī)6位數(shù) */
? ? public static String randomCode() {
? ? ? ? Integer res = (int)(Math.random()*1000000);
? ? ? ? return res+"";
? ? }
}
//加密 解密
public class SecurityUtil {
public static String md5(String password) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(password.getBytes());
return new BigInteger(1,md.digest()).toString(16);
}
public static String md5(String username,String password) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(username.getBytes());
md.update(password.getBytes());
return new BigInteger(1,md.digest()).toString(16);
}
}
//非空判斷
public class StringUtils {
? ? public static boolean isNotEmpty(String str){
? ? ? ? if(str != null && str.trim().length() != 0){
? ? ? ? ? ? return true;
? ? ? ? }
? ? ? ? return false;
? ? }
}
//郵件發(fā)送工具
@Component
public class SendEmailUtils {
? ? @Autowired
? ? private JavaMailSender javaMailSender; //注入 javaMailSender
? ? @Value("${spring.mail.username}")
? ? private? String username;? ? // 發(fā)送郵件者 郵箱 【誰發(fā)的】
? ? /**
? ? * 發(fā)送郵件
? ? * @param title? 標(biāo)題
? ? * @param titleWithName? 是否在標(biāo)題后添加 名稱
? ? * @param content? ? ? ? 內(nèi)容
? ? * @param contentWithName? 是否在內(nèi)容后添加 名稱
? ? * @param email? ? 接收者的郵箱【注冊人】
? ? */
? ? private? void? sendNormalEmail(
? ? ? ? ? ? String title,boolean titleWithName,
? ? ? ? ? ? String content, boolean contentWithName, String email ){
? ? ? ? String dName="個(gè)人博客";
? ? ? ? MimeMessage mimeMessage=null;
? ? ? ? try {
? ? ? ? ? ? mimeMessage= javaMailSender.createMimeMessage();//創(chuàng)建要發(fā)送的信息
? ? ? ? ? ? MimeMessageHelper helper=new MimeMessageHelper(mimeMessage,true);
? ? ? ? ? ? helper.setFrom(new InternetAddress(username,dName,"UTF-8")); //設(shè)置 誰發(fā)送的
? ? ? ? ? ? helper.setTo(email);//發(fā)給誰 【接收者的郵箱】
? ? ? ? ? ? title= titleWithName?title +"-"+dName:title; //標(biāo)題內(nèi)容
? ? ? ? ? ? helper.setSubject(title);//發(fā)送郵件的辯題
? ? ? ? ? ? if(contentWithName) {
? ? ? ? ? ? ? ? content += "<p style='text-align:right'>" +dName+ "</p>";
? ? ? ? ? ? ? ? content += "<p style='text-align:right'>" + NormalTools.curDate("yyyy-MM-dd HH:mm:ss")+ "</p>";
? ? ? ? ? ? }
? ? ? ? ? ? helper.setText(content,true);//發(fā)送的內(nèi)容 是否為html
? ? ? ? }catch (Exception e){
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? ? ? ? ? javaMailSender.send(mimeMessage);
? ? }
? ? /**
? ? * 發(fā)送 注冊時(shí)的驗(yàn)證碼
? ? * @param email? 接收者的郵箱【注冊人】
? ? * @param code? ? 驗(yàn)證碼
? ? */
? ? public? void? sendRegisterCode(final String email, String code){
? ? ? ? ? final StringBuffer sb= new StringBuffer();//實(shí)例化一個(gè)StringBuffer
? ? ? ? ? sb.append("<h2>"+email+",您好!<h2>")
? ? ? ? ? ? ? ? ? .append("<p style='color:red'>此次注冊的驗(yàn)證碼是:"+code+"</p>");
? ? ? ? ? new Thread(new Runnable() {
? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? sendNormalEmail("驗(yàn)證碼", true, sb.toString(), true, email);
? ? ? ? ? ? ? }
? ? ? ? ? }).start();
? ? }
? ? /**
? ? * 注冊成功時(shí)的提示郵件
? ? * @param email 接收的郵箱地址 【注冊人】
? ? * @param pwd 初始密碼
? ? * @param url 登陸地址
? ? */
? ? public void sendRegisterSuc(final String email, String pwd, String url) {
? ? ? ? final StringBuffer sb = new StringBuffer();
? ? ? ? sb.append("<h3>恭喜您,注冊成功!</h3>")
? ? ? ? ? ? ? ? .append("<h2>初始化密碼是:<b style='color:#F00'>").append(pwd).append("</b>,請不要告訴任何人!</h2>")
? ? ? ? ? ? ? ? .append("請及時(shí)<a href='").append(url).append("'>登陸網(wǎng)站</a>修改密碼。");
? ? ? ? new Thread(new Runnable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? sendNormalEmail("注冊成功", true, sb.toString(), true, email);
? ? ? ? ? ? }
? ? ? ? }).start();
? ? }
? ? /**
? ? * 注冊成功時(shí)的提示郵件
? ? * @param email 接收的郵箱地址? 【注冊人】
? ? * @param pwd 初始密碼
? ? * @param url 登陸地址
? ? */
? ? public void sendFindPwdSuc(final String email, String pwd, String url) {
? ? ? ? final StringBuffer sb = new StringBuffer();
? ? ? ? sb.append("<h3>恭喜您,密碼找回成功!</h3>")
? ? ? ? ? ? ? ? .append("<h2>系統(tǒng)隨機(jī)密碼是:<b style='color:#F00'>").append(pwd).append("</b>,請不要告訴任何人!</h2>")
? ? ? ? ? ? ? ? .append("請及時(shí)<a href='").append(url).append("'>登陸網(wǎng)站</a>修改密碼。");
? ? ? ? new Thread(new Runnable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? sendNormalEmail("成功找回密碼", true, sb.toString(), true, email);
? ? ? ? ? ? }
? ? ? ? }).start();
? ? }
? ? /**
? ? * 新用戶注冊通過
? ? * @param email 接收郵箱地址(管理員的)
? ? * @param nickname 注冊人姓名
? ? * @param regEmail 注冊人郵箱
? ? * @param url 地址
? ? */
? ? public void sendOnRegister(final String email, String nickname, String regEmail, String url) {
? ? ? ? final StringBuffer sb = new StringBuffer();
? ? ? ? sb.append("<a href='").append(url).append("'><h1>姓名:").append(nickname).append("</h1></a>");
? ? ? ? sb.append("<h3>注冊郵箱:").append(regEmail).append("</h3>");
? ? ? ? new Thread(new Runnable() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? sendNormalEmail("新用戶注冊通知", true, sb.toString(), true, email);
? ? ? ? ? ? }
? ? ? ? }).start();
? ? }
}
六.編寫 配置類
@Configuration
public class EmailConfig {
? ? @Value("http://localhost:8080/member/updatePwd")
? ? public String URL;
? ? //管理員郵箱? 此處隨便寫一個(gè)郵箱
? ? @Value("111@qq.com")
? ? public String MEMEMAIL;
}
七.編寫 controller
@RestController
@Log4j
@RequestMapping(value = "/member")
public class MemberController {
? ? @Autowired
? ? private MemberService memberService;
? ? @Autowired
? ? private SendEmailUtils sendEmailUtils;
? ? @Autowired
? ? private EmailConfig? emailConfig;
? ? /**
? ? * 發(fā)送郵箱驗(yàn)證碼
? ? * @param email? 接收者的郵箱 【注冊人】
? ? * @param request
? ? * @return
? ? */
? ? @RequestMapping(value = "/sendCode")
? ? public? String sendCode(
? ? ? ? ? ? @RequestParam(value = "email",defaultValue = "",required = true) String email,
? ? ? ? ? ? HttpServletRequest request ){
? ? ? ? try {
? ? ? ? ? ? String code =RandomTools.randomCode();//產(chǎn)生隨機(jī)的驗(yàn)證碼
? ? ? ? ? ? request.getSession().setAttribute("registerCode",code);
? ? ? ? ? ? //發(fā)送郵件開始? 發(fā)送驗(yàn)證碼
? ? ? ? ? ? log.info("開始發(fā)送郵件驗(yàn)證碼------");
? ? ? ? ? ? sendEmailUtils.sendRegisterCode(email,code);
? ? ? ? }catch (Exception e){
? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? return? "0";
? ? ? ? }
? ? ? ? return "1";
? ? }
? ? @RequestMapping(value = "/register")
? ? public ReturnMessages register(
? ? ? ? ? ? @RequestParam(value = "email",defaultValue = "",required = true) String email,
? ? ? ? ? ? @RequestParam(value = "username",defaultValue = "",required = true) String username,
? ? ? ? ? ? @RequestParam(value = "nickname",defaultValue = "",required = false) String nickname,
? ? ? ? ? ? @RequestParam(value = "smscode",defaultValue = "",required = false) String smscode,
? ? ? ? ? ? @RequestParam(value = "code",defaultValue = "",required = true) String code,
? ? ? ? ? ? HttpServletRequest request
? ? ){
? ? ? ? ? ? ReturnMessages? returnMessages=null;
? ? ? ? ? ? if (!StringUtils.isNotEmpty(email)){
? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"郵箱不能為空!",null);
? ? ? ? ? ? }
? ? ? ? ? ? if (!StringUtils.isNotEmpty(username)){
? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"用戶名不能為空!",null);
? ? ? ? ? ? }
? ? ? ? ? ? if (memberService.existMemberByemail(email)){
? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"郵箱已存在!",null);
? ? ? ? ? ? }
? ? ? ? ? ? if (memberService.existMemberByusername(username)){
? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"用戶名已存在!",null);
? ? ? ? ? ? }
? ? ? ? ? ? if (!StringUtils.isNotEmpty(code)){
? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"驗(yàn)證碼不能為空!",null);
? ? ? ? ? ? }
? ? ? ? ? ? // 此處測試的時(shí)候 無法獲取到 session 值
//? ? ? ? ? ? String registerCode = (String) request.getSession().getAttribute("registerCode");
//? ? ? ? ? ? if (!registerCode.equals(code)){
//? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"驗(yàn)證碼輸入不正確!",null);
//? ? ? ? ? ? }
? ? ? ? ? ? String pwd = RandomTools.randomCode(); //隨機(jī)密碼
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? Member member=new Member();
? ? ? ? ? ? ? ? member.setEmail(email);
? ? ? ? ? ? ? ? member.setNickname(nickname);
? ? ? ? ? ? ? ? member.setState(StateConstant.USER_STATE_CHECK_ING.toString());
? ? ? ? ? ? ? ? member.setUsername(username);
? ? ? ? ? ? ? ? member.setPassword(SecurityUtil.md5(email,pwd));
? ? ? ? ? ? ? ? member=memberService.saveMember(member);
? ? ? ? ? ? ? ? if (member !=null){
? ? ? ? ? ? ? ? ? ? //注冊成功后 通知注冊人
? ? ? ? ? ? ? ? ? ? sendEmailUtils.sendRegisterSuc(email,pwd, emailConfig.URL+"?username="+username+"&code="+pwd);//注冊成功后
? ? ? ? ? ? ? ? ? ? //注冊成功后 通知管理員
? ? ? ? ? ? ? ? ? ? sendEmailUtils.sendOnRegister(emailConfig.MEMEMAIL,username,email,"#");//注冊成功后
? ? ? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.SUCCESS,"注冊成功!",member);
? ? ? ? ? ? ? ? }else{
? ? ? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"注冊失敗!",null);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? } catch (Exception e) {
? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"注冊失??!",null);
? ? ? ? ? ? }
? ? }
? ? /**
? ? * 修改密碼
? ? * @param code? ? ? ? ? 初始密碼
? ? * @param newPassword? 新密碼
? ? * @param request
? ? * @return
? ? */
? ? @RequestMapping(value = "/updatePwd")
? ? public? ReturnMessages updatePwd(
? ? ? ? ? ? @RequestParam(value = "code",defaultValue = "",required = true) String code,
? ? ? ? ? ? @RequestParam(value = "username",defaultValue = "",required = true) String username,
? ? ? ? ? ? @RequestParam(value = "newPassword",defaultValue = "",required = true) String newPassword,
? ? ? ? ? ? HttpServletRequest request
? ? ){
? ? ? ? ? ? ReturnMessages returnMessages=null;
? ? ? ? ? ? if (!StringUtils.isNotEmpty(code)){
? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"初始密碼不能為空!",null);
? ? ? ? ? ? }
? ? ? ? ? ? if (!StringUtils.isNotEmpty(newPassword)){
? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"新密碼不能為空!",null);
? ? ? ? ? ? }
? ? ? ? ? ? Member member = memberService.findMemberByusername(username);
? ? ? ? ? ? if (member ==null){
? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"該用戶不存在!",null);
? ? ? ? ? ? }
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? if ( StringUtils.isNotEmpty(code) && StringUtils.isNotEmpty(newPassword)){
? ? ? ? ? ? ? ? ? ? member.setPassword(SecurityUtil.md5(member.getEmail(),newPassword));
? ? ? ? ? ? ? ? ? ? member=memberService.updateMember(member);
? ? ? ? ? ? ? ? ? ? if (member !=null){
? ? ? ? ? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.SUCCESS,"修改密碼成功!",member);
? ? ? ? ? ? ? ? ? ? }else{
? ? ? ? ? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"修改密碼失?。?,null);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }else{
? ? ? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"修改密碼失??!",null);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }catch (Exception e){
? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"修改密碼失敗!",null);
? ? ? ? ? ? }
? ? }
? ? /**
? ? * 找回密碼
? ? * @param email? ? 用戶郵箱
? ? * @param request
? ? * @return
? ? */
? ? @RequestMapping(value ="/findPwd")
? ? public? ReturnMessages findPwd(
? ? ? ? ? ? @RequestParam(value = "email",defaultValue = "",required = true) String email,
? ? ? ? ? ? HttpServletRequest request
? ? ){
? ? ? ? ? ReturnMessages returnMessages=null;
? ? ? ? ? if (!StringUtils.isNotEmpty(email)){
? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"郵箱不能為空!",null);
? ? ? ? ? }
? ? ? ? ? Member member= memberService.findMemeberByemail(email);
? ? ? ? ? if (member ==null){
? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"該用戶不存在!",null);
? ? ? ? ? }
? ? ? ? ? try {
? ? ? ? ? ? ? String url="http:192.168.0.17:8080/member/login";
? ? ? ? ? ? ? String randPwd = RandomTools.randomCode();//隨機(jī)產(chǎn)生一個(gè)密碼
? ? ? ? ? ? ? member.setPassword(SecurityUtil.md5(email,randPwd));
? ? ? ? ? ? ? member=memberService.updateMember(member);
? ? ? ? ? ? ? //發(fā)送郵件通知 用戶
? ? ? ? ? ? ? sendEmailUtils.sendFindPwdSuc(email,randPwd,url);
? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.SUCCESS,"找回密碼成功!",member);
? ? ? ? ? }catch (Exception e){
? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"找回密碼失敗!",null);
? ? ? ? ? }
? ? }
? ? /**
? ? * 登錄
? ? * @param email? ? ? 郵箱
? ? * @param password? 密碼
? ? * @param request
? ? * @return
? ? */
? ? @RequestMapping(value = "/login")
? ? public? ReturnMessages login(
? ? ? ? ? ? @RequestParam(value = "email",defaultValue = "",required = true) String email,
? ? ? ? ? ? @RequestParam(value = "password",defaultValue = "",required = true) String password,
? ? ? ? ? ? HttpServletRequest request
? ? ){
? ? ? ? ReturnMessages returnMessages=null;
? ? ? ? try {
? ? ? ? ? ? if (!StringUtils.isNotEmpty(email)){
? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"郵箱不能為空!",null);
? ? ? ? ? ? }
? ? ? ? ? ? if (!StringUtils.isNotEmpty(password)){
? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"密碼不能為空!",null);
? ? ? ? ? ? }
? ? ? ? ? ? Member member=memberService.findMemeberByemail(email);
? ? ? ? ? ? if (member== null){
? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"用戶不存在!",null);
? ? ? ? ? ? }
? ? ? ? ? ? String pwd=SecurityUtil.md5(email,password);
? ? ? ? ? ? if (member.getPassword().equals(pwd)){
? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.SUCCESS,"登錄成功!",null);
? ? ? ? ? ? }else{
? ? ? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"密碼錯(cuò)誤,登錄失??!",null);
? ? ? ? ? ? }
? ? ? ? }catch (Exception e){
? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? return? new? ReturnMessages(RequestState.ERROR,"登錄失??!",null);
? ? ? ? }
? ? }
}
---------------------
作者:zhaihuilin0986
來源:CSDN
原文:https://blog.csdn.net/zhaihuilin0986/article/details/78530657
版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請附上博文鏈接!