丹阳市建设局网站,网站建设与管理综合实践,网站做关键词,个人网页发邮件1、创建邮箱需要你有1个邮箱#xff0c;可以正常发送邮件。尽可能有另1个邮箱#xff0c;可以正常接收。2、打开已有/创建邮箱#xff0c;申请授权码2.1 登录网页版邮箱3、安装邮件客户端在工作中#xff0c;一般都会通过邮箱进行沟通。在工作的电脑上#xff0c;安…发邮件1、创建邮箱需要你有1个邮箱可以正常发送邮件。尽可能有另1个邮箱可以正常接收。2、打开已有/创建邮箱申请授权码2.1 登录网页版邮箱3、安装邮件客户端在工作中一般都会通过邮箱进行沟通。在工作的电脑上安装一个邮箱客户端方便发送和接收邮件。手机上尽量也安装一个邮箱客户端方便后续就接收入职通知或者面试通知等。后续使用了日志技术代码在发送异常的时候也会通过邮件提示。4、配置SpringMail4.1 配置项目在qingqing项目中的admin-api中配置dependencies dependency groupIdcom.javasm/groupId artifactIdcommon/artifactId version0.0.1-SNAPSHOT/version /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-mail/artifactId /dependency /dependencies4.2 配置项目server: tomcat: max-swallow-size: 10MB max-http-form-post-size: 10MB port: 8088 spring: servlet: multipart: max-file-size: 10MB max-request-size: 10MB application: name: admin_api datasource: #配置数据库连接池种类 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/qingqing?useUnicodetruecharacterEncodingUTF-8allowMultiQueriestrueserverTimezoneGMT%2B8useSSLfalseallowPublicKeyRetrievaltrue username: root password: root druid: initial-size: 5 max-active: 100 min-idle: 10 data: redis: host: localhost port: 6379 password: javasm database: 2 task: execution: pool: core-size: 10 max-size: 20 queue-capacity: 1000 scheduling: pool: size: 10 mail: protocol: smtp host: smtp.163.com port: 465 username: 17335592100163.com password: CLQ5XnDsUs3nxbRS properties: mail: smtp: auth: true ssl: enable: true mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl5、纯Java发邮件package com.javasm.qingqing; import jakarta.mail.Message; import jakarta.mail.Session; import jakarta.mail.Transport; import jakarta.mail.internet.InternetAddress; import jakarta.mail.internet.MimeMessage; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import java.util.Properties; SpringBootTest public class JavaMailTest { //这个案例是纯Java实现的比较繁琐看一看就可以了 //通过这个案例来了解发送邮件底层都需要哪些角色 Test void f1() throws Exception { //定义账号信息 //发件人 String account 17335592100163.com; //收件人 String to chengdujavasm126.com; //发件人密码 String password CLQ5XnDsUs3nxbRS; //SMTP信息 Properties properties new Properties(); //连接协议 properties.put(mail.ransport.protocol,smtp); //邮箱域名 properties.put(mail.smtp.host,smtp.163.com); //端口号 默认是25 properties.put(mail.smtp.port,465); //服务端认证 properties.put(mail.smtp.auth,true); //安全连接 properties.put(mail.smtp.ssl.enable,true); //初始化会话对象 Session session Session.getDefaultInstance(properties); //发消息对象 Message msg new MimeMessage(session); //配置 发送人信息 msg.setFrom(new InternetAddress(account)); //配置 收件人信息 msg.setRecipient(Message.RecipientType.TO,new InternetAddress(to)); //配置 抄送人信息 msg.setRecipient(Message.RecipientType.CC,new InternetAddress(account)); //邮件标题 msg.setSubject(今日天气); //邮件内容 msg.setText(晴天0~11°); //邮差对象 这封信是由邮差交给收件人 Transport transport session.getTransport(); //配置 邮箱的用户名和密码 transport.connect(account,password); //邮差 发送邮件 transport.sendMessage(msg,msg.getAllRecipients()); } } 6、SpringMail发送邮件6.1 纯文本package com.javasm.qingqing; import jakarta.annotation.Resource; import jakarta.mail.MessagingException; import jakarta.mail.internet.MimeMessage; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.mail.MailProperties; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; SpringBootTest public class SpringMailTest { //SpringMail的客户端对象 Resource JavaMailSender javaMailSender; //获取配置文件中关于邮件的配置 Resource MailProperties mailProperties; //收件人信息 private final static String to chengdujavasm126.com; //发送纯文本 Test void f1() throws Exception { //邮件客户端对象中获取消息对象 MimeMessage mimeMessage javaMailSender.createMimeMessage(); //消息辅助对象 MimeMessageHelper helper new MimeMessageHelper(mimeMessage); //发件人 String from mailProperties.getUsername(); helper.setFrom(from); //收件人 helper.setTo(to); //标题 helper.setSubject(今日新闻-----红军城又失守了); //内容 helper.setText(忽如一夜冻风来); //发送 javaMailSender.send(mimeMessage); } }6.2 HTML Resource GameService gameService; Test void f2() throws Exception { MimeMessage mimeMessage javaMailSender.createMimeMessage(); MimeMessageHelper helper new MimeMessageHelper(mimeMessage); helper.setFrom(mailProperties.getUsername()); helper.setTo(to); helper.setSubject(测试HTML的案例); //拼接HTML代码 ListGame list gameService.list(); StringBuffer html new StringBuffer(); html.append(h1游戏列表/h1); //循环table html.append(table styleborder:1px solid #000;text-align:center;); html.append(trtdID/tdtd游戏名/tdtd图标/td/tr); list.forEach(game -{ html.append(tr); html.append(td); html.append(game.getId()); html.append(/td); html.append(td); html.append(game.getName()); html.append(/td); html.append(td); html.append(img src); html.append(game.getIcon()); html.append( stylewidth:50px;height:50px); html.append(/td); html.append(/tr); }); html.append(/table); html.append(h2 stylecolor:red;游戏列表结束/h2); //一张图片 html.append(img srchttp://cd.ray-live.cn/imgs/headpic/pic_0.jpg); //设置邮件内容 helper.setText(html.toString(),true); javaMailSender.send(mimeMessage); }6.3 本地图片Test void f3() throws Exception { MimeMessage mimeMessage javaMailSender.createMimeMessage(); //multipart true 表示支持上传文件 MimeMessageHelper helper new MimeMessageHelper(mimeMessage, true); helper.setFrom(mailProperties.getUsername()); helper.setTo(to); helper.setSubject(本地图片上传测试); //内容 StringBuilder html new StringBuilder(); html.append(img srccid:ei); helper.setText(html.toString(),true); //本地找一张图片 File file new File(D://save/pic_140.jpg); //文件上传 helper.addInline(ei,file); //发送 javaMailSender.send(mimeMessage); }6.4 附件Test void f4() throws Exception { MimeMessage mimeMessage javaMailSender.createMimeMessage(); MimeMessageHelper helper new MimeMessageHelper(mimeMessage, true); helper.setFrom(mailProperties.getUsername()); helper.setTo(to); helper.setSubject(测试附件); String html img srccid:ei; helper.setText(html,true); File img new File(D://save/pic_140.jpg); helper.addInline(ei,img); helper.addAttachment(abc.png,img); //附件 File fu1 new File(D://save/t1.docx); helper.addAttachment(test.docx,fu1); //发送 javaMailSender.send(mimeMessage); }7 、封装工具类package com.javasm.qingqing.common.utils; import jakarta.annotation.Resource; import jakarta.mail.MessagingException; import jakarta.mail.internet.MimeMessage; import org.springframework.boot.autoconfigure.mail.MailProperties; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Component; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.Set; Component public class MailUtil { Resource JavaMailSender javaMailSender; Resource MailProperties mailProperties; public void sendMail(String email , String title, String count, File... files){ MimeMessage mimeMessage javaMailSender.createMimeMessage(); try { MimeMessageHelper helper new MimeMessageHelper(mimeMessage, true); //配置发件人 helper.setFrom(mailProperties.getUsername()); //配置收件人 helper.setTo(email); //标题 helper.setSubject(title); //内容 helper.setText(count,true); //判断附件 if (files ! null){ for (File file : files){ helper.addAttachment(file.getName(),file); } } //发送 javaMailSender.send(mimeMessage); } catch (MessagingException e) { throw new RuntimeException(e); } } private static final SetString IMAGE_EXTENSIONS Set.of( jpg,jpeg,png,gif,bmp,wbp ); //用来判断file是不是图片类型 public boolean isImage(File file){ //文件对象null || 文件不存在||文件不是文件是文件夹 if (file null || !file.exists() || !file.isFile()){ return false; } //扩展名 String fileName file.getName(); //后缀 int indexOf fileName.lastIndexOf(.); if (indexOf -1) return false; //获取扩展名 String extension fileName.substring(indexOf 1).toLowerCase(); if (!IMAGE_EXTENSIONS.contains(extension)){ return false; } //校验实际的内容是不是 try { BufferedImage image ImageIO.read(file); return image ! null; } catch (IOException e) { return false; } } } 8、重置密码前端页面点击重置按钮 → 请求API接口 → 服务端发送邮件到用户邮箱 → 用户点击链接跳转到前端页面 → 获取参数传入后端接口 → 判断参数是否正确返回对应的json → 前端确认页面可以根据返回的不同json提示不同的信息 → 跳转到用户修改密码的表单页面8.1 引入Thymeleaf是SpringBoot默认提供的页面策略。html的模板不需要手动拼接HTMLdependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-thymeleaf/artifactId /dependency8.2 创建页面在resources/templates 文件夹中新建HTML这是一个默认的存储thymeleaf页面的路径不能随意更改必须叫templates!DOCTYPE html html langen head meta charsetUTF-8 title密码找回/title /head body div h1 stylecolor: gold密码找回/h1 /div div h2 stylecolor: aqua下方是找回密码的超链接请点击/h2 h3亲爱的用户span th:text${username}/span/h3 /div div a th:href{http://127.0.0.1:8088/login/checkemail(t${token})}点击我找回密码此链接10分钟内有效/a /div /body /html8.3 发送邮件接口RestController RequestMapping(/login) public class LoginController { Resource LoginService loginService; GetMapping(/password/back) public R backPassword(String email){ loginService.sendBackPasswordEmail(email); return R.ok(); } }Servicepackage com.javasm.qingqing.login.service.impl; import com.javasm.qingqing.adminuser.entity.AdminUser; import com.javasm.qingqing.adminuser.service.AdminUserService; import com.javasm.qingqing.common.utils.JWTUtil; import com.javasm.qingqing.common.utils.MailUtil; import com.javasm.qingqing.login.service.LoginService; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; Service public class LoginServiceImpl implements LoginService { Resource MailUtil mailUtil; Resource TemplateEngine templateEngine; Resource AdminUserService adminUserService; Override public void sendBackPasswordEmail(String email) { //根据email地址查询用户信息 AdminUser adminUser adminUserService.getByEmail(email); if (adminUser ! null){ //发送邮件 //确认 发送的html是什么 //从thymeleaf中获取html代码 //import org.thymeleaf.context.Context; Context context new Context(); context.setVariable(username,adminUser.getNickname()); //获取token字符串 String token JWTUtil.generateEmail(email); context.setVariable(token,token); //获取静态html backpassword.html 页面 传入 值 context对象 String html templateEngine.process(backpassword,context); mailUtil.sendMail(email,密码找回,html); } } } 8.4 修改JWTUtilpublic class JWTUtil { //生成的服务器秘钥 private static final String keyStr Oon2pDRDSxQ8uVt4zuDc1ogr9p0JjVJlNd2aVMqPWE; private static final Integer expUidTime 1000 * 60 * 60 * 24 * 15; private static final Integer expEmailTime 1000 * 60 * 10; public static final String Server_Token javasm_token; public static String generateEmail(String email) { MapString,Object map new HashMap(); map.put(email,email); return generateToken(map,expEmailTime); } //加密的方法把uid加密成Token字符串 public static String generateUid(String uid){ MapString,Object map new HashMap(); map.put(uid,uid); return generateToken(map,expUidTime); } private static String generateToken(MapString,Object map,Integer expTime){ //因为加密的字符串要给一个过期时间 //记录什么时候生成的Token Date time new Date(); //设置过期时间这个字符串多久过期失效 Date lastTime new Date(time.getTime() expTime); //生成一个Key SecretKey key Keys.hmacShaKeyFor(Decoders.BASE64.decode(keyStr)); return Jwts.builder() .setClaims(map) //加密的数据 .setIssuedAt(time) //标准签名加密的时间 .setExpiration(lastTime) //过期时间 .signWith(key) //指定签名KeyHeader中的秘钥 .compact(); } public static String parseEmail(String token){ return parse(email,token); } public static String parseUid(String token){ return parse(uid,token); } //解密 private static String parse(String mapKey ,String token){ //解密 获取和加密一样的key SecretKey key Keys.hmacShaKeyFor(Decoders.BASE64.decode(keyStr)); String string null; try { JwsClaims jws Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); Claims body jws.getBody(); //获取加密前的字符串 string body.get(mapKey, String.class); } catch (ExpiredJwtException e) { throw new JavasmException(ExceptionEnum.Token_Expired_Error); } catch (UnsupportedJwtException e) { throw new JavasmException(ExceptionEnum.Token_Unsupported_Error); } catch (SignatureException e) { throw new JavasmException(ExceptionEnum.Token_Signature_Error); } catch (Exception e) { throw new JavasmException(ExceptionEnum.SYSTEM_ERROR); } return string; } //生成服务端知道的秘钥只有服务端能知道不能泄露 //不能随意更改如果秘钥更改了之前生成的所有Token都会失效 //这个方法不会频繁执行只会在生产秘钥的时候执行1次 private static void generateKey(){ //指定算法 SecretKey key Keys.secretKeyFor(SignatureAlgorithm.HS256); //生成加密的字符串 String encode Encoders.BASE64.encode(key.getEncoded()); System.out.println(encode); } }8.5 校验Token的接口GetMapping(/checkemail) public R checkEmail(RequestParam(t) String token){ AdminUser adminUser loginService.checkEmail(token); return R.ok(adminUser); }Override public AdminUser checkEmail(String token) { String email JWTUtil.parseEmail(token); AdminUser adminUser adminUserService.getByEmail(email); return adminUser; }Log4J21、介绍日志技术用来记录程序运行的轨迹SpringBoot自带了一个日志框架logbacklog4j2和 logback 都使用了统一的日志门面日志门面是一个类似接口的框架所有的日志框架都实现了日志门面。在使用日志的时候如果从locback切换到log4j2是不会影响编码的。为什么需要使用日志技术?现在我们的代码产生的日志和异常信息都是输出在idea的控制台上。以后代码发布到线上之后程序是要在Linux下运行的。Linux不能在一个idea中运行程序也就没有控制台也无法打断点去debug在linux下调试Bug只能通过输出日志去调试在线上排查bug必须通过观察日志去排查。Log4j2能够实现把不同级别的日志分配到不同的文件夹和文件中方便排查。目前国内最流行的日志框架。三个组件LoggerappenderLayout2、日志级别ALL Trace Debug Info Warn Error Fatal OFF常用DebugInfoWarnErrorDebug调试阶段使用的日志级别之前都是使用System.out输出日志使用完了之后必须删除不能留下痕迹改变使用System.out的习惯调试阶段的日志不需要删除可以一直保留只需要在正式运行的时候把不想看的debug级别日志屏蔽掉就可以了Info程序正常运行过程中输出的日志一般这个级别是不会被屏蔽的有一些位置值的正常输出或者提醒包括线上调试追踪bug一般的默认级别的日志Warn没有严格的要求在什么位置使用程序运行过程中一些值存在危险/有可能 产生异常作为危险的提示Error出现在异常中异常处理之后显示的日志级别Error的出现代表程序抛出了Exception需要让程序员/运维 知道/注意 的内容一般Error级别的日志都需要通过邮件通知管理员/项目组成员3、测试RestController RequestMapping(/admin/user) public class AdminUserController { /** * import org.apache.logging.log4j.LogManager; * import org.apache.logging.log4j.Logger; */ Logger logger LogManager.getLogger(AdminUserController.class); GetMapping(/f1) public R f1(){ logger.debug(-------------------我是Debug); logger.info(-------------------我是Info); logger.warn(-------------------我是警告); logger.error(-------------------我是Error!!!!); return R.ok(); } }Slf4j import com.javasm.qingqing.common.exception.R; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; RestController RequestMapping(/admin/user2) Slf4j public class AdminUserController2 { GetMapping(/f1) public R f1(){ log.debug(-------------------我是Debug); log.info(-------------------我是Info); log.warn(-------------------我是警告); log.error(-------------------我是Error!!!!); return R.ok(); } } 4、引入依赖因为当前框架已经有了Logback日志需要在web的依赖中把它移除掉需要把web的依赖放到第一位并且检查项目中不能有多个Web的依赖把公共模块common中的web依赖拿到admin-api的pom.xml中dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId exclusions exclusion groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-logging/artifactId /exclusion /exclusions /dependency加入新的依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-log4j2/artifactId /dependency dependency groupIdcom.lmax/groupId artifactIddisruptor/artifactId version3.4.2/version /dependency添加log4j2.xml?xml version1.0 encodingUTF-8? configuration !-- 记录的一些变量 没有生效-- appenders !-- 控制台输出的日志格式 -- console nameConsole targetSYSTEM_OUT PatternLayout pattern%d{HH:mm:ss} %-5level %class{36} %L %M ----- %msg%n / /console !-- fileName输出路径 filePattern命名规则 -- !-- name 配置的名字唯一 -- !-- 这个配置的作用是指定 DEBUG级别的日志输出到对应文件中-- RollingFile nameRollingFileDebug fileNameD:/logs/debug.log filePatternD:/logs/$${date:yyyy-MM-dd}/debug-%d{yyyy-MM-dd}-%i.log Filters !--Filters决定日志事件能否被输出。过滤条件有三个值ACCEPT(接受), DENY(拒绝) or NEUTRAL(中立).-- !--如果接受/拒绝日志到这里就会记录然后结束如果是中立则会继续记录.-- !-- level将被过滤的级别。 onMatch:默认值是NEUTRAL onMismatch默认是DENY -- !-- 过滤的日志级别是debug-- ThresholdFilter levelDEBUG/ !-- 如果当前记录的日志级别info则返回 onMatch 的值小于info则onMismatch 的值-- ThresholdFilter levelINFO onMatchDENY onMismatchNEUTRAL / /Filters !-- 输出格式 -- PatternLayout pattern%d{HH:mm:ss.SSS} [%t] %-5level %class{36} %L %M - %msg%n / Policies !-- 单个日志文件的大小限制 -- SizeBasedTriggeringPolicy size100 MB / /Policies !-- 最多保留20个日志文件 -- DefaultRolloverStrategy max20 / /RollingFile RollingFile nameRollingFileInfo fileNameD:/logs/info.log filePatternD:/logs/$${date:yyyy-MM-dd}/info-%d{yyyy-MM-dd}-%i.log Filters ThresholdFilter levelINFO / ThresholdFilter levelWARN onMatchDENY onMismatchNEUTRAL / /Filters !-- 输出格式 -- PatternLayout pattern%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n / Policies !-- SizeBasedTriggeringPolicy单个文件的大小限制 -- SizeBasedTriggeringPolicy size100 MB / /Policies !-- DefaultRolloverStrategy同一个文件下的最大文件数 -- DefaultRolloverStrategy max20 / /RollingFile RollingFile nameRollingFileWarn fileNameD:/logs/warn.log filePatternD:/logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log Filters ThresholdFilter levelWARN / ThresholdFilter levelERROR onMatchDENY onMismatchNEUTRAL / /Filters PatternLayout pattern[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n / Policies !--TimeBasedTriggeringPolicy modulatetrue interval1/ -- SizeBasedTriggeringPolicy size100 MB / /Policies !--最多保留20个日志文件 -- DefaultRolloverStrategy max20 min0 / /RollingFile RollingFile nameRollingFileError fileNameD:/logs/error.log filePatternD:/logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log Filters ThresholdFilter levelERROR / ThresholdFilter levelFATAL onMatchDENY onMismatchNEUTRAL / /Filters PatternLayout attern[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n / Policies !--TimeBasedTriggeringPolicy modulatetrue interval1/ -- SizeBasedTriggeringPolicy size100 MB / /Policies !--最多保留20个日志文件 -- DefaultRolloverStrategy max20 min0 / /RollingFile !-- name 标签名字 subject 邮件标题 to:发送给谁多个人用,分隔 aaa163.com,bbbqq.com from:发送邮件的账户 需要在邮箱后台设置中开启SMTP服务 smtpProtocol smtp 发送的协议 smtpUsername 发送账号 smtpPassword 发送密码 smtpHost 服务器地址 POP3服务器: pop.163.com SMTP服务器: smtp.163.com IMAP服务器: imap.163.com smtpPort 发送端口 163的是465 加上会报错 Got bad greeting from SMTP host smtp.163.com, port 465 , response [EOF] -- !--SMTP nameMail subject过往云烟的异常信息 tochengdujavasm126.com,cxds5536163.com from19008239181163.com smtpPasswordKXNZHOZDMLTVWHOZ smtpUsername19008239181163.com smtpProtocolsmtp smtpHostsmtp.163.com bufferSize10 ignoreExceptionsfalse smtpDebugtrue ThresholdFilter levelERROR onMatchACCEPT/ PatternLayout pattern%d %p [%C] [%t] %m%n/pattern /PatternLayout /SMTP-- /appenders loggers !-- 设置当前的默认日志级别-- !--是SpringBoot项目的默认日志级别-- root levelINFO !--配置生效的位置如果不配置则不输出-- appender-ref refConsole/ appender-ref refRollingFileDebug/ appender-ref refRollingFileInfo/ appender-ref refRollingFileWarn/ appender-ref refRollingFileError/ /root !--额外配置的logger-- !--记录druid-sql的记录-- logger namedruid.sql.Statement leveldebug additivityfalse appender-ref refdruidSqlRollingFile/ /logger !-- log4j2自带的过滤标签额外指定 特定包的日志级别 -- logger nameorg.springframework.web levelerror/logger logger nameorg.springframework.core levelerror/logger logger nameorg.springframework.beans levelerror/logger logger nameorg.springframework.boot levelerror/logger !--单独设置自己的包 为 debug级别-- !--单独配置 自己的包-- logger namecom.javasm leveldebug additivitytrue !--输入日志到邮件-- !--appender-ref refMail /-- /logger !--异步日志配置-- !--AsyncLogger nameorg.springframework levelerror includeLocationtrue AppenderRef refRollingFileError/AppenderRef /AsyncLogger AsyncLogger nameorg.mybatis levelerror includeLocationtrue AppenderRef refRollingFileError/AppenderRef /AsyncLogger AsyncLogger namecom.alibaba.druid levelerror includeLocationtrue AppenderRef refRollingFileError/AppenderRef /AsyncLogger AsyncRoot leveldebug includeLocationtrue appender-ref refConsole/ appender-ref refRollingFileInfo/ appender-ref refRollingFileWarn/ appender-ref refRollingFileError/ /AsyncRoot-- /loggers /configuration符号PatternLayout格式化符号说明 %p 或 %level输出日志信息的优先级即DEBUGINFOWARNERRORFATAL。 %d输出日志时间点的日期或时间默认格式为ISO8601也可以在其后指定格式如%d{yyyy/MM/dd HH:mm:ss,SSS}。 %r输出自应用程序启动到输出该log信息耗费的毫秒数。 %t输出产生该日志事件的线程名。 %class输出日志信息所属的类目通常就是所在类的全名。 %M输出产生日志信息的方法名。 %F输出日志消息产生时所在的文件名称。 %L输出代码中的行号。 %m 或%msg或%message:输出代码中指定的具体日志信息。 %n输出一个回车换行符Windows平台为“rn”Unix平台为“n”。 %x输出和当前线程相关联的NDC(嵌套诊断环境)尤其用到像java servlets这样的多客户多线程的应用中。 %%输出一个“%”字符。 另外还可以在%与格式字符之间加上修饰符来控制其最小长度、最大长度、和文本的对齐方式。如 1)%-20“-”号表示左对齐,不满足20个字符则以空格代替。 2)%.30指定输出category的名称最大的长度是30如果category的名称长度大于30的话就会将左边多出的字符截掉但小于30的话也不会补空格。