图表插件和发送邮件

本文详细介绍了出口报运系统的实现过程,包括调用流程、海关报运平台搭建、电子报运及结果查询等功能,并利用Echarts展示统计分析图表,如厂家销售统计、产品销量排行榜等,同时讲解了邮件发送功能的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今日内容

  • 出口报运
  • 图表报表工具
  • 统计分析模块
  • 发送邮件

第一章 出口报运( 重点 )

1. 调用流程分析

alt

2. 海关报运平台搭建

2.1 导入sql脚本到数据库

image-20201021154607265
2.2 导入海关程序

将jk_export导入到export_parent的同级目录, 然后使用idea导入此程序

2.3 部署海关程序

alt
2.4 程序使用地址
电子报运提交(post)
http://localhost:5003/ws/export/user
电子保存结果查询(get)
http://localhost:5003/ws/export/user/报运单id

3. 发送电子报运

3.1 导入海关提供的标准对象

alt
3.2 ExportController
/**
* 海关电子报运
*/
@RequestMapping(value = "/exportE", name = "海关电子报运")
public String exportE(String id) {

exportService.exportE(id);
return "redirect:/cargo/export/list.do";
}
3.3 ExportService
void exportE(String id);
@Override
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
/**
* 查看报运结果
*/
@RequestMapping(value = "/findExportResult", name = "查看报运结果")
public String findExportResult(String id) {

exportService.findExportResult(id);
return "redirect:/cargo/export/list.do";
}
4.2 ExportService
void findExportResult(String id);
@Override
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 {

@Autowired
private ExportDao exportDao;

@Autowired
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 添加定时任务的配置
<?xml version="1.0" encoding="UTF-8"?>
<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. 快速入门

  1. 下载echarts组件
  2. html引入echarts组件
  3. div容器(宽、高)
  4. 通过js初始化echarts图形报表
<!DOCTYPE html>
<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数据,就可以完成其他的图表展示了

alt

第三章 统计分析模块(ajax sql)

1. 需求说明

  • 厂家销售统计 (统计每个厂家的销售额)
  • 产品的销量排行榜(统计产品销售数量前10名厂家)
  • 系统访问压力图(统计每个小时访问系统的人员数量)

2. 环境搭建

2.1 架构图

alt
2.2 创建模块,建立依赖

export_stat_interface\pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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

<?xml version="1.0" encoding="UTF-8"?>
<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;

@Service
public class StatServiceImpl implements StatService {

@Autowired
private StatDao statDao;

@Override
public List<Map> findFactoryCharts(String companyId) {
return statDao.findFactoryCharts(companyId);
}

@Override
public List<Map> findSellCharts(String companyId) {
return statDao.findSellCharts(companyId);
}

@Override
public List<Map> findOnlineCharts(String companyId) {
return statDao.findOnlineCharts(companyId);
}
}
2.4 复制配置文件

alt
2.5 添加启动文件

alt
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;

@Controller
@RequestMapping("/stat")
public class StatController extends BaseController {

@Reference
private StatService statService;

/**
* 跳转图形页面
*/
@RequestMapping(value = "/toCharts", name = "跳转图形页面")
public String toCharts(String chartsType) {
return "/stat/stat-" + chartsType;
}


}

3. 厂家销售统计

3.1 StatController
/**
* 厂家销量统计
*/
@RequestMapping(value = "/factoryCharts", name = "厂家销量统计")
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
@ResponseBody
@RequestMapping(value = "/sellCharts", name = "产品销售统计")
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
@ResponseBody
@RequestMapping(value = "/onlineCharts", name = "在线人数统计")
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邮件服务器:接收邮件

    alt

POP3/IMAP对比:

alt

2. 发送邮件准备工作

2.1 引入坐标
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.4</version>
</dependency>
2.2 申请授权码

alt
2.3 加入工具类,并修改

image-20201021181331135
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() {
@Override
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,添加保存用户后发送一封邮件的功能

@RequestMapping(value = "/edit", name = "部门新增")
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. 发送邮件功能问题分析

alt
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.YHL

谢谢您的肯定

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值