今日内容
- 出口报运
- 图表报表工具
- 统计分析模块
- 发送邮件
第一章 出口报运( 重点 )
1. 调用流程分析

2. 海关报运平台搭建
2.1 导入sql脚本到数据库

2.2 导入海关程序
将jk_export导入到export_parent的同级目录, 然后使用idea导入此程序
2.3 部署海关程序

2.4 程序使用地址
电子报运提交(post)
http://localhost:5003/ws/export/user
电子保存结果查询(get)
http://localhost:5003/ws/export/user/报运单id
3. 发送电子报运
3.1 导入海关提供的标准对象

3.2 ExportController
/**
* 海关电子报运
*/
"/exportE", name = "海关电子报运") (value =
public String exportE(String id) {
exportService.exportE(id);
return "redirect:/cargo/export/list.do";
}
3.3 ExportService
void exportE(String id);
public void exportE(String id) {
// 查询报运单信息,封装到ExportVo
Export export = exportDao.selectByPrimaryKey(id);
// 实体对象
ExportVo exportVo = new ExportVo();
BeanUtils.copyProperties(export,exportVo);
exportVo.setExportId(id);
exportVo.setExportDate(new Date());
// 查询保运单下的货物信息
ExportProductExample exportProductExample = new ExportProductExample();
exportProductExample.createCriteria().andExportIdEqualTo(id);
List<ExportProduct> exportProductList = exportProductDao.selectByExample(exportProductExample);
for (ExportProduct eportProduct : exportProductList) {
ExportProductVo exportProductVo = new ExportProductVo();
BeanUtils.copyProperties(eportProduct,exportProductVo);
exportProductVo.setExportProductId(eportProduct.getId());
exportVo.getProducts().add(exportProductVo);
}
// 调用海关平台,然后将exportVo发出去
WebClient.create("http://localhost:5003/ws/export/user").post(exportVo);
// 修改当前报运单的状态
export.setState(1);
exportDao.updateByPrimaryKeySelective(export);
}
4. 查询报运结果
4.1 ExportController
/**
* 查看报运结果
*/
"/findExportResult", name = "查看报运结果") (value =
public String findExportResult(String id) {
exportService.findExportResult(id);
return "redirect:/cargo/export/list.do";
}
4.2 ExportService
void findExportResult(String id);
public void findExportResult(String id) {
try {
// 调用接口接收返回结果
ExportResult exportResult = WebClient.create("http://localhost:5003/ws/export/user/" + id).get(ExportResult.class);
// 根据结果跟新报运单信息
Export export = new Export();
export.setId(id);
export.setState(exportResult.getState());
// 保存数据
exportDao.updateByPrimaryKeySelective(export);
// 根据exportResult对象中的products更新保运单中的信息
for (ExportProductResult exportResultProduct : exportResult.getProducts()) {
ExportProduct exportProduct = new ExportProduct();
exportProduct.setId(exportResultProduct.getExportProductId());
// 将查询到的税设置到实体保存到数据库
exportProduct.setTax(exportResultProduct.getTax());
exportProductDao.updateByPrimaryKeySelective(exportProduct);
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("查询失败,请检查输入的内容");
}
}
5. 整合定时任务(作业)
要求每天的1,9,17点进行查询
5.1 创建定时任务的类
在export_cargo模块下创建定时任务的类
package com.itheima.service.cargo.job;
import com.itheima.dao.cargo.ExportDao;
import com.itheima.dao.cargo.ExportProductDao;
import com.itheima.domain.cargo.Export;
import com.itheima.domain.cargo.ExportExample;
import com.itheima.domain.cargo.ExportProduct;
import com.itheima.vo.ExportProductResult;
import com.itheima.vo.ExportResult;
import org.apache.cxf.jaxrs.client.WebClient;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
public class ExportJob {
private ExportDao exportDao;
private ExportProductDao exportProductDao;
public void updateExportResult() {
//1 查询状态为1的报运单
ExportExample exportExample = new ExportExample();
exportExample.createCriteria().andStateEqualTo(1L);
List<Export> exportList = exportDao.selectByExample(exportExample);
for (Export export : exportList) {
try {
//2 调用海关平台查询
ExportResult exportResult = WebClient.create("http://localhost:5003/ws/export/user/" + export.getId()).get(ExportResult.class);
//3 更新报运单状态
export.setId(exportResult.getExportId());//id
export.setState(exportResult.getState());//状态
export.setRemark(exportResult.getRemark());//备注
exportDao.updateByPrimaryKeySelective(export);//一定支持动态SQL
//4 更新报运单下货物的税
for (ExportProductResult product : exportResult.getProducts()) {
ExportProduct exportProduct = new ExportProduct();
exportProduct.setId(product.getExportProductId());
exportProduct.setTax(product.getTax());
exportProductDao.updateByPrimaryKeySelective(exportProduct);
}
}catch (Exception e){
System.out.println("未查到相关信息");
}
}
}
}
5.2 添加定时任务的配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--1.配置Job:自定义java类 -->
<bean id="myJob" class="com.itheima.service.cargo.job.ExportJob"/>
<!--2.配置JobDetail:执行任务来的方法-->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<!--1.确定任务类-->
<property name="targetObject" ref="myJob"/>
<!--2.确认任务的方法-->
<property name="targetMethod" value="updateExportResult"></property>
</bean>
<!--3.配置Trigger:根据时间规则,触发方法执行-->
<bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<!--1.指定时间规则-->
<property name="cronExpression" value="0 0 1,9,17 * * ? *"></property>
<!--2.指定JobDetail-->
<property name="jobDetail" ref="jobDetail"></property>
</bean>
<!--4.配置Scheduler:统一管理配置trigger-->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<array>
<ref bean="trigger"></ref>
</array>
</property>
</bean>
</beans>
第二章 图表报表工具 Echarts(了解)
1. 简介
Echarts 是由百度前端团队开发的一款开源的基于js图形报表组件,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器,底层依赖轻量级的矢量图形库 ZRender,提供直观,交互丰富,可高度个性化定制的数据可视化图表。
2018年3月全球著名开源社区Apache宣布百度ECharts进入Apache孵化器。
官网地址:https://echarts.apache.org/
2. 快速入门
- 下载echarts组件
- html引入echarts组件
- div容器(宽、高)
- 通过js初始化echarts图形报表
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>图像练习</title>
<!-- 1.引入 ECharts 文件 -->
<script src="plugins/echarts/echarts.min.js"></script>
</head>
<body>
<!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data:['销量']
},
xAxis: {
data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
</html>
我们学习echarts发现基于快速入门的代码,只需要修改option数据,就可以完成其他的图表展示了

第三章 统计分析模块(ajax sql)
1. 需求说明
- 厂家销售统计 (统计每个厂家的销售额)
- 产品的销量排行榜(统计产品销售数量前10名厂家)
- 系统访问压力图(统计每个小时访问系统的人员数量)
2. 环境搭建
2.1 架构图

2.2 创建模块,建立依赖
export_stat_interface\pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>export_parent</artifactId>
<groupId>com.itheima</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>export_stat_interface</artifactId>
<dependencies>
<dependency>
<groupId>com.itheima</groupId>
<artifactId>export_domain</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
export_stat_service\pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>export_parent</artifactId>
<groupId>com.itheima</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>export_stat_service</artifactId>
<dependencies>
<dependency>
<groupId>com.itheima</groupId>
<artifactId>export_stat_interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.itheima</groupId>
<artifactId>export_dao</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
export_manager_web\pom.xml
<dependency>
<groupId>com.itheima</groupId>
<artifactId>export_stat_interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
2.3 代码实现
// dao
import java.util.List;
import java.util.Map;
/*
统计分析
*/
public interface StatDao {
// 厂家销售统计 (统计每个厂家的销售额)
List<Map> findFactoryCharts(String companyId);
// 产品的销量排行榜(统计产品销售数量最高的前10名)
List<Map> findSellCharts(String companyId);
// 系统访问压力图(每个小时访问系统的人员数量)
List<Map> findOnlineCharts(String companyId);
}
//service接口
package com.itheima.service.stat;
import java.util.List;
import java.util.Map;
/*
统计分析
*/
public interface StatService {
// 厂家销售统计 (统计每个厂家的销售额)
List<Map> findFactoryCharts(String companyId);
// 产品的销量排行榜(统计产品销售数量最高的前10名)
List<Map> findSellCharts(String companyId);
// 系统访问压力图(每个小时访问系统的人员数量)
List<Map> findOnlineCharts(String companyId);
}
// 实现类
package com.itheima.service.stat.impl;
import com.alibaba.dubbo.config.annotation.Service;
import com.itheima.dao.stat.StatDao;
import com.itheima.service.stat.StatService;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.Map;
public class StatServiceImpl implements StatService {
private StatDao statDao;
public List<Map> findFactoryCharts(String companyId) {
return statDao.findFactoryCharts(companyId);
}
public List<Map> findSellCharts(String companyId) {
return statDao.findSellCharts(companyId);
}
public List<Map> findOnlineCharts(String companyId) {
return statDao.findOnlineCharts(companyId);
}
}
2.4 复制配置文件

2.5 添加启动文件

2.6 实现页面跳转
在export_manager_web
模块的com.itheima.web.controller.stat
包下建立StatController
类
import com.alibaba.dubbo.config.annotation.Reference;
import com.itheima.service.stat.StatService;
import com.itheima.web.controller.BaseController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
"/stat") (
public class StatController extends BaseController {
private StatService statService;
/**
* 跳转图形页面
*/
"/toCharts", name = "跳转图形页面") (value =
public String toCharts(String chartsType) {
return "/stat/stat-" + chartsType;
}
}
3. 厂家销售统计
3.1 StatController
/**
* 厂家销量统计
*/
"/factoryCharts", name = "厂家销量统计") (value =
public List<Map> factoryCharts() {
return statService.findFactoryCharts(getCompanyId());
}
3.2 StatDao.xml
<!--厂家销售统计-->
<select id="findFactoryCharts" resultType="java.util.Map">
SELECT
factory_name `name`,
SUM(amount) `value`
FROM
`co_contract_product`
WHERE company_id = #{companyId}
GROUP BY factory_name
</select>
3.3 stat-factory.jsp
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
$.get('/stat/factoryCharts.do').done(function (data) {
var titles = [];
for (let e of data) {
titles.push(e.name);
}
// 使用刚指定的配置项和数据显示图表。
myChart.setOption({
title: {
text: '厂家销售统计',
subtext: '',
x: 'center'
},
legend: {
orient: 'vertical',
left: 'left',
data: titles
},
tooltip: {
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
series: [
{
name: '访问来源',
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
data: data,
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
})
});
</script>
4. 产品的销量排行榜
4.1 StatController
"/sellCharts", name = "产品销售统计") (value =
public List<Map> sellCharts() {
return statService.findSellCharts(getCompanyId());
}
4.2 StatDao.xml
<select id="findSellCharts" resultType="java.util.Map">
SELECT product_no as `name` , SUM(cnumber) AS `value`
FROM `co_contract_product`
WHERE company_id = #{companyId}
GROUP BY product_no
ORDER BY `value` DESC
LIMIT 10
</select>
4.3 stat-sell.jsp
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
$.get('/stat/sellCharts.do').done(function (data) {
var titles = [];
var values = [];
for (let e of data) {
titles.push(e.name);
values.push(e.value);
}
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(
option = {
title: {
left: 'center',
text: '产品销量排行',
},
xAxis: {
type: 'category',
data: titles,
axisLabel: {
rotate: 70
}
},
yAxis: {
type: 'value'
},
series: [{
data: values,
type: 'bar'
}]
}
)
});
</script>
5. 系统访问压力图
5.1 StatController
"/onlineCharts", name = "在线人数统计") (value =
public List<Map> onlineCharts() {
return statService.findOnlineCharts(getCompanyId());
}
5.2 StatDao.xml
<!--系统访问压力图-->
<select id="findOnlineCharts" resultType="java.util.Map">
SELECT a.A1 AS `name`,IFNULL(b.`value`,0) AS `value`
FROM `st_online_info` AS a
LEFT JOIN
(SELECT DATE_FORMAT(`time`,"%H") AS mytime,COUNT(1) AS `value` FROM `st_sys_log`
WHERE company_id = #{companyId}
GROUP BY mytime) AS b
ON a.A1 = b.mytime
</select>
5.3 stat-online.jsp
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
$.get('/stat/sellCharts.do').done(function (data) {
var titles = [];
var values = [];
for (let e of data) {
titles.push(e.name);
values.push(e.value);
}
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(
option = {
title: {
left: 'center',
text: '产品销量排行',
},
xAxis: {
type: 'category',
data: titles,
axisLabel: {
rotate: 70
}
},
yAxis: {
type: 'value'
},
series: [{
data: values,
type: 'bar'
}]
}
)
});
</script>
第四章 发送邮件(重点)
1. 邮件传输的过程
SMTP邮件服务器:发送邮件
POP3/IMAP邮件服务器:接收邮件
POP3/IMAP对比:

2. 发送邮件准备工作
2.1 引入坐标
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.4</version>
</dependency>
2.2 申请授权码

2.3 加入工具类,并修改

2.4 代码
package com.itheima.utils;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
/**
* 发邮件工具类
*/
public final class MailUtil {
//下面两项需要我们修改
private static final String USER = "jyangha***n@163.com"; // 发件人箱地址
private static final String PASSWORD = "LBPOKD*******PDF"; // 授权码
/**
* @param to 收件人邮箱
* @param title 标题
* @param content 邮件正文
*/
/* 发送验证信息的邮件 */
public static boolean sendMail(String to, String title, String content) {
try {
final Properties props = new Properties();
props.setProperty("mail.transport.protocol", "SMTP");//设置发邮件的协议
props.setProperty("mail.host", "smtp.163.com");//设置发邮件的地址(smtp邮箱服务器地址)
props.setProperty("mail.smtp.auth", "true");// 指定验证为true
// 发件人的账号
props.put("mail.user", USER);
//发件人的密码
props.put("mail.password", PASSWORD);
// 构建授权信息,用于进行SMTP进行身份验证
Authenticator authenticator = new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
// 用户名、密码
String userName = props.getProperty("mail.user");
String password = props.getProperty("mail.password");
return new PasswordAuthentication(userName, password);
}
};
// 使用环境属性和授权信息,创建邮件会话
Session mailSession = Session.getInstance(props, authenticator);
// 创建邮件消息
MimeMessage message = new MimeMessage(mailSession);
// 设置发件人
String username = props.getProperty("mail.user");
InternetAddress form = new InternetAddress(username);
message.setFrom(form);
// 设置收件人
InternetAddress toAddress = new InternetAddress(to);
message.setRecipient(Message.RecipientType.TO, toAddress);
// 设置邮件标题
message.setSubject(title);
// 设置邮件的内容体
message.setContent(content, "text/html;charset=UTF-8");
// 发送邮件
Transport.send(message);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
public static void main(String[] args) throws Exception { // 做测试用
sendMail("jyhlbx@outlook.com" , "测试邮件,无需回复。", "你好,这是一封测试邮件");
System.out.println("发送成功");
}
}
3. 实现发送邮件功能
修改UserController
,添加保存用户后发送一封邮件的功能
"/edit", name = "部门新增") (value =
public String edit(User user) {
String oldPwd = user.getPassword();
if (StringUtils.isNotEmpty(oldPwd)){
String pwd = new Md5Hash(oldPwd,user.getEmail(),2).toString();
user.setPassword(pwd);
}
if (StringUtils.isEmpty(user.getId())) {
//1. 设置主键
user.setId(UUID.randomUUID().toString());
//2. 设置企业信息
user.setCompanyId(getCompanyId());
user.setCompanyName(getCompanyName());
userService.save(user);
// 这里发送邮件
String to = user.getEmail();
String title = "saas平台--用户新增成功";
String content = "恭喜您,您的账号已经在saas平台开通成功,请使用当前邮箱作用账号,使用" + oldPwd + "作为密码进行登录";
MailUtil.sendMail(to, title, content);
} else {
userService.update(user);
}
//重定向到list方法
return "redirect:/system/user/list.do";
}
4. 发送邮件功能问题分析
