图书电子商务网站建设专门学习网站建设读什么专业
图书电子商务网站建设,专门学习网站建设读什么专业,牙膏的网站建设方案,php网站连接数据库教程通过一个小的业务点出发#xff0c;搭建一个可以实例使用的项目工程#xff0c;将各种知识点串联起来; 实战演练专题中#xff0c;每一个项目都是可以独立运行的#xff0c;包含若干知识点#xff0c;甚至可以不做修改直接应用于生产项目#xff1b;
今天的实战项目主要…通过一个小的业务点出发搭建一个可以实例使用的项目工程将各种知识点串联起来; 实战演练专题中每一个项目都是可以独立运行的包含若干知识点甚至可以不做修改直接应用于生产项目今天的实战项目主要解决的业务需求为每日新增用户统计生成报表并邮件发送给相关人本项目将包含以下知识点基于 MySql 的每日新增用户报表统计如何统计每日新增用户若日期不连续如何自动补 0定时执行报表统计任务MyBatis MySql 数据操作邮件发送Thymeleaf 引擎实现报表模板渲染I. 需求拆解需要相对来说属于比较明确的了目的就是实现一个自动报表统计的任务查询出每日的用户新增情况然后推送给指定的用户因此我们将很清晰的知道我们需要干的事情定时任务这里重点放在如何来支持这个任务的定时执行通常来说定时任务会区分为固定时刻执行 间隔时长执行两种注意这种区分主要是为了方便理解如每天五点执行的任务也可以理解为每隔 24h 执行一次前者常见于一次性任务如本文中的每天统计一次这种就是相对典型的固定时刻执行的任务后者常见于轮询式任务如常见的应用探活(每隔 30s 发一个 ping 消息判断服务是否健在定时任务的方案非常多有兴趣的小伙伴可以关注一波“一灰灰 blog”公众号蹲守一个后续本文将直接采用 Spring 的定时任务实现需求场景对这块不熟悉的小伙伴可以看一下我之前的分享的博文180801-Spring 之定时任务基本使用篇 - 一灰灰 Blog[2]180803-Spring 定时任务高级使用篇 - 一灰灰 Blog[3]每日新增用户统计每日新增用户统计实现方式挺多的比如举几个简单的实现思路基于 redis 的计数器一天一个 key当天有新用户时同步的实现计数器1基于数据库新增一个统计表包含如日期 新增用户数 活跃用户数 等字段有新用户注册时对应日期的新增用户数活跃用户数 1老用户今日首次使用时活跃用户数 1上面两个方案都需要借助额外的库表来辅助支持本文则采用直接统计用户表根据注册时间来聚合统计每日的新增用户数优点简单无额外要求适用于数据量小的场景比如用户量小于百万的缺点用户量大时数据库压力大关于如何使用 mysql 进行统计每日新增用户不熟悉的小伙伴推荐参考博主之前的分享文章220707-MySql 按时、天、周、月进行数据统计 - 一灰灰 Blog[4]报表生成推送用户接下来就是将上面统计的数据生成报表然后推送给用户首先是如何将数据生成报表其次则是如何推送给指定用户将数据组装成报表的方式通常取决于你选择的推送方式如飞书、钉钉之类的有对应的开发 api可以直接推送富文本本文的实现姿势则选择的是通过邮件的方式进行发送why?飞书、钉钉、微信之类的需要授权对于不使用这些作为办公软件的小伙伴没什么意义短信需要钱....对于邮件大家应该都有无论是 qq 邮箱还是工作邮箱基本上对于想要直接跑本文的小伙伴来说没有什么额外的门槛关于 java/spring 如何使用邮箱对此不太熟悉的小伙伴可以参考博主之前的分享文章【中间件】SpringBoot 系列之邮件发送姿势介绍 | 一灰灰 Blog[5]上面文章中介绍的是 FreeMaker 来实现模板渲染本文则介绍另外一个知识点借助 Thymleaf 来实现数据报表的生成 一篇文章获取这么多知识点就问你开不开心 O(∩_∩)OII. 分布实现1. 项目搭建首选搭建一个基本的 SpringBoot 应用相信这一步大家都很熟悉了若有不懂的小伙伴请点赞、评论加博主好友手把手教你不收费最终的项目依赖如下dependencies !-- 邮件发送的核心依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-mail/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-thymeleaf/artifactId /dependency dependency groupIdcom.google.guava/groupId artifactIdguava/artifactId version31.1-jre/version /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.2.2/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId /dependency /dependencies别看上面好像依赖了不少包实际上各有用处spring-boot-starter-web: 提供 web 服务spring-boot-starter-mail: 发邮件就靠它mybatis-spring-boot-starter: 数据库操作我们的用户存在 mysql 中这里使用 mybatis 来实现 db 操作又一个知识点来了收好不谢2. 数据准备文末的源码包含库表结构初始化数据可以直接使用既然模拟的是从数据库中读取每日新增用户所以我们准备了一张表CREATE TABLE u1 ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 主键id, name varchar(64) NOT NULL DEFAULT COMMENT name, email varchar(512) NOT NULL DEFAULT COMMENT email, create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 生成时间, update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), KEY idx_name (name) ) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4 COMMENTu1测试;接下来准备写入一些数据为了模拟某些天没有新增用户贴心的一灰灰博主给大家提供基于 python 的数据生成脚本源码如下 (python3对 python 不熟的小伙伴可以到博主的站点进补一下超链[6])import datetime def create_day_time(n): now datetime.datetime.now() now now - datetime.timedelta(days n) return now.strftime(%Y-%m-%d %H:%S:%M) vals [] for i in range(0, 100): if (i % 32 % 6) 0: # 模拟某一天没有用户的场景 continue vals.append(f({i}_灰灰, {i}huiemail.com, {create_day_time(i % 32)}, {create_day_time(i % 32)})) values ,\n\t.join(vals) sqls fINSERT INTO story.u1 (name, email, create_time, update_time) VALUES \n{values}; print(sqls)3. 全局配置数据准备完毕之后接下来配置一下 db、email 相关的参数resources/application.yml 文件内容如下spring: #邮箱配置 mail: host: smtp.163.com from: xhhuiblog163.com # 使用自己的发送方用户名 授权码填充 username: password: default-encoding: UTF-8 properties: mail: smtp: auth: true starttls: enable: true required: true datasource: url: jdbc:mysql://127.0.0.1:3306/story?useUnicodetruecharacterEncodingUTF-8useSSLfalseserverTimezoneAsia/Shanghai username: root password: thymeleaf: mode: HTML encoding: UTF-8 servlet: content-type: text/html cache: false mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.git.hui.demo.report.dao.po上面的配置分为三类数据库相关连接信息用户名密码 mybatis 配置thymleaf模板渲染相关email: 邮箱配置相关请注意若使用博主的源码在本地运行时请按照前面介绍的邮箱博文中手把手的教程获取您自己的邮箱授权信息填在上面的 username, password 中4. 数据报表统计实现接下来就正式进入大家喜闻乐见的编码实现环节我们直接使用 mybaits 来实现数据库操作定义一个统计的接口/** * author YiHui */ public interface UserStatisticMapper { /** * 统计最近多少天内的新增用户数 * * param days 统计的天数从当前这一天开始 * return */ ListUserStatisticPo statisticUserCnt(int days); }接口中定义了一个 PO 对象就是我们希望返回的数据其定义就非常清晰简单了时间 数量Data public class UserStatisticPo { private String day; private Integer count; }上面定义的知识接口具体首先当然是放在 mybatis 的传统 xml 文件中根据前面 application.yml 配置我们的 xml 文件需要放在 resources/mapper 目录下具体实现如下?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.git.hui.demo.report.dao.UserStatisticMapper resultMap idcountMap typecom.git.hui.demo.report.dao.po.UserStatisticPo result columnday propertyday/ result columncount propertycount/ /resultMap !-- 统计用户新增 -- select idstatisticUserCnt resultMapcountMap SELECT date_table.day as day, IFNULL(data.cnt, 0) as count from (select DATE_FORMAT(create_time, %Y-%m-%d) day, count(id) cnt from u1 GROUP BY day) data right join (SELECT date : DATE_ADD(date, interval - 1 day) day from (SELECT date : DATE_ADD(CURDATE(), interval 1 day) from u1) days limit #{days}) date_table on date_table.day data.day /select /mapper重点看一下上面的 sql 实现为什么会一个 join 逻辑那我们稍稍思考若我们直接通过日期进行 format 之后再 group 一下统计计数会有什么问题给大家 3s 的思考时间1s2s3s好的 3s 时间到现在公布答案当某一天一个新增用户都没有的时候会发生什么事情会出现这一天的数据空缺即返回的列表中少了一天不连续了如果前段的小伙伴基于这个列表数据进行绘图很有可能出现异常所以出于系统的健壮性考虑即传说中的鲁棒性我们希望若某一天没有数据则对应的计数设置为 0具体的 sql 说明就不展开了请查看博文获取更多MySql 按时、天、周、月进行数据统计[7]5. 报表生成实现数据统计出来之后接下来就是基于这些数据来生成我们报表我们借助 Thymleaf 来实现因此先写一个 html 模板resources/templates/report.html!DOCTYPE html html xmlns:thhttp://www.thymeleaf.org head meta charsetUTF-8 title th:text${vo.htmlTitle}每日用户统计/title /head style .title22 { font: 16px/24px bold; position: relative; display: block; padding: 0 6px; margin-left: -6px; margin-bottom: 12px; font-size: 22px; font-weight: 550; } .container { background: #fff; overflow: auto; padding: 6px; margin: 6px; font-family: Microsoft YaHei UI, Microsoft YaHei, 微软雅黑, SimSun, 宋体; } .content { overflow: auto; padding: 6px 12px; margin: 6px; } table { border: none; border-collapse: collapse; table-layout: fixed; } .thead { font: 14px/20px bold; font-weight: 550; background: #eaeaea; line-height: 1.5em; } .tbody { font: 15px/20px normal; font-weight: 540; background: #fff; } tr td { padding: 6px 12px; border: 1px solid #d8d8d8; max-width: 600px; } /style body div classcontainer div classcontent div classtitle22 stylecolor: red; th:text${vo.tableTitle}统计标题/div table thead classthead tr td classthead stylebackground:#eaeaea;日期/td td stylemin-width: 50px; color: #4040e1新增用户/td /tr /thead tbody classtbody tr th:eachitem: ${vo.list} td classthead stylebackground:#eaeaea; th:text${item.day}2022-08-01/td td stylemin-width: 50px; color: #4040e1 th:text${item.count}1/td /tr /tbody /table /div /div /body /html一个非常简单的 table 模板需要接收三个数据与之对应的 vo 对象我们定义如下Data public class StatisticVo { // 表格数据项即日期 数量的列表 private ListUserStatisticPo list; // 网页的标题 private String htmlTitle; // 表格标题 private String tableTitle; }接下来就是拿到数据之后将它与模板渲染得到我们希望的数据这里主要借助的是org.thymeleaf.spring5.SpringTemplateEngine核心实现如下Service public class StatisticAndReportService { Autowired private UserStatisticMapper userStatisticMapper; Autowired private JavaMailSender javaMailSender; Autowired private Environment environment; Autowired private SpringTemplateEngine templateEngine; public StatisticVo statisticAddUserReport() { ListUserStatisticPo list userStatisticMapper.statisticUserCnt(30); StatisticVo vo new StatisticVo(); vo.setHtmlTitle(每日新增用户统计); vo.setTableTitle(String.format(【%s】新增用户报表, LocalDate.now())); vo.setList(list); return vo; } public String renderReport(StatisticVo vo) { Context context new Context(); context.setVariable(vo, vo); String content templateEngine.process(report, context); return content; } }模板渲染就一行templateEngine.process(report, context)第一个参数为模板名就是上面的 html 文件名对于模板文件、静态资源怎么放放在那儿这个知识点当然也可以在一灰灰的站点获取超链[8]第二个参数用于封装上下文传递模板需要使用的参数5. 邮件发送报表生成之后就是将它推送给用户我们这里选定的是邮箱方式具体实现也比较简单但是在最终部署到生产环境如阿里云服务器时可能会遇到坑同样明显的知识点博主会没有分享么当然不会没有了Email 生产环境发送排雷指南你值得拥有[9]/** * 发送邮件的逻辑 * * param title * param content * throws MessagingException */ public void sendMail(String title, String content) throws MessagingException { MimeMessage mimeMailMessage javaMailSender.createMimeMessage(); MimeMessageHelper mimeMessageHelper new MimeMessageHelper(mimeMailMessage, true); //邮件发送人从前面的配置参数中拿若没有配置则使用默认的xhhuiblog163.com mimeMessageHelper.setFrom(environment.getProperty(spring.mail.from, xhhuiblog163.com)); //邮件接收人可以是多个 mimeMessageHelper.setTo(bangzewu126.com); //邮件主题 mimeMessageHelper.setSubject(title); //邮件内容 mimeMessageHelper.setText(content, true); // 解决linux上发送邮件时抛出异常 JavaMailSender no object DCH for MIME type multipart/mixed Thread.currentThread().setContextClassLoader(javax.mail.Message.class.getClassLoader()); javaMailSender.send(mimeMailMessage); }上面的实现直接写死了收件人邮箱即我本人的邮箱各位大佬在使用的时候请记得替换一下啊上面的实现除了发送邮件这个知识点之外还有一个隐藏的获取配置参数的知识点即environment#getProperty()有兴趣的小伙伴翻博主的站点吧6. 定时任务上面几部基本上就把我们的整个任务功能都实现了从数据库中统计出每日新增用户然后借助 Thymleaf 来渲染模板生成报告然后借助 email 进行发送最后的一步就是任务的定时执行直接借助 Spring 的 Schedule 来完成我们的目标这里我们希望每天 4:15 分执行这个任务如下配置即可// 定时发送每天4:15分统计一次发送邮件 Scheduled(cron 0 15 4 * * ?) // 下上面这个是每分钟执行一次用于本地测试 // Scheduled(cron 0/1 * * * * ?) public void autoCalculateUserStatisticAndSendEmail() throws MessagingException { StatisticVo vo statisticAddUserReport(); String content renderReport(vo); sendMail(新增用户报告, content); }7. 测试最后测试演练一下启动方法如下除了基本的启动注解之外还指定了 mapper 接口位置开启定时任务感兴趣的小伙伴可以试一下干掉这两个注解会怎样评论给出你的实测结果吧EnableScheduling MapperScan(basePackages com.git.hui.demo.report.dao) SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class); } }当然我再实际测试的时候不可能真等到早上四点多来看是否执行大晚上还是要睡觉的因此本地测试的时候可以将上面定时任务改一下换成每隔一分钟执行一次接一个 debug 的中间图打开的内容展示此外源码除了实现了定时推送之外也提供了一个 web 接口访问之后直接可以查看报表内容方便大家调样式实现如下Controller public class StatisticReportRest { Autowired private StatisticAndReportService statisticAndReportSchedule; GetMapping(path report) public String view(Model model) { StatisticVo vo statisticAndReportSchedule.statisticAddUserReport(); model.addAttribute(vo, vo); return report; } }8.一灰灰的干货总结最后进入一灰灰的保留环节这么“大”一个项目坐下来的当然是得好好盘一盘它的知识点了前面的各小节内容中有穿插的指出相应的知识点接下来如雨的知识点将迎面袭来不要眨眼Spring 定时任务Schedule怎么用-180801-Spring 之定时任务基本使用篇 - 一灰灰 Blog[10]多个任务串行并行是否会相互影响自定义线程池怎么整一个异常会影响其他么-Spring 定时任务高级使用篇 - 一灰灰 Blog[11]数据库统计每日新增mysql 直接统计日新增sql 怎么写时间不连续如何规避-MySql 按时、天、周、月进行数据统计 - 一灰灰 Blog[12]mybatis 操作 db 怎么玩-Mybatis 系列教程[13]模板渲染数据报表生成直接字符串拼接还是模板引擎的渲染更多的 spring web 知识点 -一灰灰的 SpringWeb 专栏 | 免费[14]邮件发送怎么发邮件-SpringBoot 无障碍使用邮箱服务[15]如何避免上线不采坑 -Email 生产环境发送排雷指南你值得拥有[16]除了上面比较突出的知识点之外当然还有其他的如 Spring 如何读取配置参数SpringMVC 如何向模板中传递上下文模板语法静态资源怎么放等等