基于springboot及爬虫数据实现的疫情统计项目
1.项目简介
1.1 项目技术要求
-
spring boot的常见应用
-
业务功能的开发思路
-
爬虫的底层原理
-
对技术的应用有一定思考
1.2 爬虫的基础知识
1.2.1 搜索引擎
“搜索引擎”是一种帮助用户搜索他们需要内容的计算机程序,本质是连接人与内容。
存储数据的处理方式
如:一篇文章 -> 语义分析 -> 关键字提取 -> 根据关键字及出现次数等 -> 倒排存储
关键字搜索
关键字相关的近义词、反义词、关联信息(ip、地址、用户信息)
1.2.2 爬虫分类
通用型爬虫(搜索引擎使用)
采集的数据是整个网站的数据,不论数据是何种形态、格式,使用通用的方法来存储和处理。
垂直型爬虫(对特定内容的采集)
采集的数据是指定的,格式是指定的,使用个性化的方法来处理。
网站的首页作为种子, 爬虫去采集能够分解出多少不重复的子链接,及其数据。
采集/下载页面 -> 分解为数据本身(存储) 、新的链接(依次向下爬取,类似树的深度遍历)-> 直到没有新链接代表采集完成 (链接使用队列来存储)。
1.2.3 爬虫数据的分析
浏览器开发者工具
分析数据源
腾讯新闻出品:https://news.qq.com/zt2020/page/feiyan.htm#/?nojump=1
工具的打开方式:F12 / Ctrl+Shift+I / 更多工具 -> 开发者工具 / 右键 -> 检查 -> 选中Network -> Preserve log(保存持续的日志), 重新刷新页面,可以看到网页所有的请求连接和返回数据。
想拿到表格中国内疫情的数据情况:
分析的方式
通过搜索框,搜索想要获得数据的具体数值,如:944/758等等。
分析后的请求地址
https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5
返回数据的格式是json
丁香医生出品
https://ncov.dxy.cn/ncovh5/view/pneumonia?scene=2&clicktime=1579579384&enterid=1579579384&from=singlemessage&isappinstalled=0
分析的方式同上。
分析后的请求地址
https://ncov.dxy.cn/ncovh5/view/pneumonia?scene=2&from=singlemessage&isappinstalled=0
返回数据的格式是html。
postman(模拟http请求的工具)
验证分析出来的请求地址,在排除上下文环境后,是否依然能够拿到数据。比如有的请求,依赖cookie、依赖动态的参数等等。
爬虫破解问题
拿到数据是核心的一步
-
公开数据只要是非恶意就允许采集的,非恶意是指模仿人的行为采集的行为,不会高并发或者恶意攻击
-
隐私数据都是有强大的加密处理的,防爬虫的手段是安全领域内的一大问题
2.解析数据
2.1 认识JSON
JSON = JavaScript Object Notation(JavaScript对象表示法)
本质上,是存储和交换文本信息的语法。是一种轻量级的文本数据格式。
java领域内解析json的工具:gson、fastjson、jackson
JSON 和 Java实体类
JSON | JAVA实体类 |
---|---|
string | java.lang.String |
number | java.lang.Number (Double) |
true\false | java.lang.Boolean |
null | null |
array | java.util.List (ArrayList) |
object | java.util.Map (LinkedTreeMap) |
2.2 Gson
是google推出的,用来在json数据和java对象之间进行转换的类库。
```java Gson gson = new Gson(); Gson gson1 = new GsonBuilder().create();
// 将对象obj转化为json字符串 String jsonStr = gson.toJson(Obj); // 将json字符串转化为java对象 T obj = gson.fromJson(jsonStr,class) ```
2.2.1 引入gson依赖
```xml
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
```
2.2.2 确认要转化的数据格式
java
import lombok.AllArgsConstructor;
import lombok.Data;
@Data @AllArgsConstructor
public class DataBean {
private String area;
private int nowConfirm;
private int confirm;
private int heal;
private int dead;
}
2.2.3 解析文本数据
java
public class DataHandler {
public static void main(String[] args) throws Exception{
getData();
}
public static List<DataBean> getData() throws Exception {
// Gson gson = new Gson();
// Gson gson1 = new GsonBuilder().create();
// Map map = gson.fromJson(testStr,Map.class);
// System.out.println(map);
// 读取文件中的文本内容 然后再转化为java对象
// File file = new File("tmp.txt");
FileReader fr = new FileReader("tmp.txt");
char[] cBuf = new char[1024];
int cRead = 0;
StringBuilder builder = new StringBuilder();
while ((cRead = fr.read(cBuf)) > 0) {
builder.append(new String(cBuf, 0, cRead));
}
fr.close();
// System.out.println(builder.toString());
Gson gson = new Gson();
Map map = gson.fromJson(builder.toString(), Map.class);
System.out.println(map);
ArrayList areaList = (ArrayList) map.get("areaTree");
Map dataMap = (Map) areaList.get(0);
ArrayList childrenList = (ArrayList) dataMap.get("children");
// 遍历然后转化
List<DataBean> result = new ArrayList<>();
for (int i = 0; i < childrenList.size(); i++) {
Map tmp = (Map) childrenList.get(i);
String name = (String)tmp.get("name");
Map totalMap = (Map) tmp.get("total");
double nowConfirm = (Double)totalMap.get("nowConfirm");
double confirm = (Double)totalMap.get("confirm");
double heal = (Double)totalMap.get("heal");
double dead = (Double)totalMap.get("dead");
DataBean dataBean = new DataBean(name,(int)nowConfirm,(int)confirm, (int)heal,(int)dead);
result.add(dataBean);
}
System.out.println(result);
return result;
}
}
2.3 将数据展示在页面中
2.3.1 编写service和controller
java
import com.duing.bean.DataBean;
import java.util.List;
public interface DataService {
List<DataBean> list();
}
java
import com.duing.bean.DataBean;
import com.duing.handler.DataHandler;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DataServiceImpl implements DataService {
@Override
public List<DataBean> list() {
List<DataBean> result = null;
try {
result = DataHandler.getData();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
java
import com.duing.bean.DataBean;
import com.duing.service.DataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;
@Controller
public class DataController {
@Autowired
private DataService dataService;
@GetMapping("/")
public String list(Model model){
List<DataBean> list = dataService.list();
model.addAttribute("dataList",list);
return "list";
}
}
2.3.2 编写页面(注意已引入thymeleaf的maven依赖)
```html
国内疫情情况如下
地区 | 现有确诊 | 累计确诊 | 治愈 | 死亡 |
---|---|---|---|---|
name | nowConfirm | confirm | heal | dead |
```
2.4 转为实时数据
复习get和post请求,分别在使用场景、参数传递方式、数据大小限制、安全性等方面的异同。
连接时间和读取时间 :
-
连接时间 : 发送请求端连接到url目标地址端的时间,受到距离长短和网络速度的影响
-
读取时间 : 指连接成功后获取数据的时间,受到数据量和服务器处理速度的影响
用java代码模拟http请求 :
-
通过创建url打开远程链接 (HttpURLConnection)
-
设置相关参数(超时时间和请求头等等)
-
发送请求
-
接收结果(使用InputStream和BufferedReader)
```java public static String doGet(String urlStr) { HttpURLConnection conn = null; InputStream is = null; BufferedReader br = null; StringBuilder result = new StringBuilder(); try { URL url = new URL(urlStr); // 通过url打开一个远程连接 强转类型 conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); // 连接时间和读取时间 conn.setConnectTimeout(15000); conn.setReadTimeout(60000); // 设定请求头参数的方式:如指定接收json数据 服务端的key值为content-type // conn.setRequestProperty("Accept", "application/json"); // 发送请求 conn.connect(); if (conn.getResponseCode() != 200) { // TODO 此处应该增加异常处理 return "error code"; } is = conn.getInputStream(); br = new BufferedReader(new InputStreamReader(is, "UTF-8")); String line; // 逐行读取 不为空就继续 while ((line = br.readLine()) != null) { result.append(line); System.out.print(line); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (br != null) br.close(); if (is != null) is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return result.toString();
}
```
2.5 使用Jsoup解析html格式数据
Jsoup是html的解析器,可以解析html文本和直接解析URL地址。本质上是通过DOM、CSS以及类似jQuery的方法来取出和操作数据。
java
Document document = Jsoup.parse(htmlStr);
System.out.println(document);
//通过标签名找到元素
Elements elements = document.getElementsByTag("p");
System.out.println(elements);
document.getElementsById //通过id找到元素
Element element = document.select("a[href]");//还支持使用正则表达式查找元素
2.5.1 增加了controller方法
java
@GetMapping("/list/{id}")
public String listById(Model model, @PathVariable String id) {
List<DataBean> list = dataService.listById(Integer.parseInt(id));
model.addAttribute("dataList", list);
return "list";
}
@PathVariavle 将接收到的地址数据,映射到方法的参数中
2.5.2 完善service
java
@Override
public List<DataBean> listById(int id) {
if (id == 2) {
return JsoupHandler.getData();
}
return list();
}
2.5.3 处理数据的方法
java
public static String urlStr = "https://ncov.dxy.cn/ncovh5/view/pneumonia?" + "scene=2&from=singlemessage&isappinstalled=0";
public static ArrayList<DataBean> getData() {
ArrayList<DataBean> result = new ArrayList<>();
try {
Document doc = Jsoup.connect(urlStr).get();
// Elements scripts = doc.select("script");
// 找到指定的标签数据
Element oneScript = doc.getElementById("getAreaStat");
String data = oneScript.data();
// 字符串截取出json格式的数据
String subData = data.substring(data.indexOf("["), data.lastIndexOf("]") + 1);
// System.out.println(subData);
Gson gson = new Gson();
ArrayList list = gson.fromJson(subData, ArrayList.class);
for (int i = 0; i < list.size(); i++) {
Map map = (Map) list.get(i);
String name = (String) map.get("provinceName");
double nowConfirm = (Double) map.get("currentConfirmedCount");
double confirm = (Double) map.get("confirmedCount");
double heal = (Double) map.get("curedCount");
double dead = (Double) map.get("deadCount");
DataBean dataBean = new DataBean(name, (int) nowConfirm, (int) confirm, (int) heal, (int) dead);
result.add(dataBean);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
2.5.4 验证
分别访问 http://localhost:8080/list/1 和 http://localhost:8080/list/2 ,通过省份的名称来区分不同渠道的数据结果。
2.6 增加数据存储逻辑
2.6.1 引入相关的依赖
```xml
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
```
2.6.2 配置数据库
xml
spring.datasource.url=jdbc:mysql://localhost:3306/epidemic?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456
2.6.3 使用mybatis-plus进行增删改查的操作
创建mapper
java
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.duing.bean.DataBean;
public interface DataMapper extends BaseMapper<DataBean> { }
扫描mapper的注解
在主程序入口类中添加
java
@MapperScan("com.duing.mapper")
创建service及其实现类
注意泛型是要处理的实体类
java
import com.baomidou.mybatisplus.extension.service.IService;
import com.duing.bean.DataBean;
import java.util.List;
public interface DataService extends IService<DataBean> {}
java
// 泛型 分别是mapper 以及 实体类
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.duing.bean.DataBean;
import com.duing.mapper.DataMapper;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DataServiceImpl extends ServiceImpl<DataMapper,DataBean>
implements DataService { }
改造实体类databean
此时要满足,存在无参构造器以及可被序列化,同时指定具体映射的表名,通过@TableName
java
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data @AllArgsConstructor
@NoArgsConstructor
@TableName("illness")
public class DataBean implements Serializable {
private String area;
private int nowConfirm;
private int confirm;
private int heal;
private int dead;
}
初始化数据存储的逻辑
@PostConstruct 修饰的方法,在服务器加载Servlet时运行,而且只执行一次
改造逻辑:首先将DataHandler声明为组件 @Component
java
@Autowired
private DataService dataService;
@PostConstruct
public void saveData() {
try {
List<DataBean> dataBeans = getData();
// 先将数据清空 然后存储数据
dataService.remove(null);
dataService.saveBatch(dataBeans);
} catch (Exception e) {
e.printStackTrace();
}
}
@Scheduled 使用前需要在主程序入口类上打开开关
java
@EnableScheduling
在方法上使用注解的参数
-
@Scheduled(fixedRate = 10000)
指定频率的执行任务,从方法执行开始就计时 -
假设方法执行5s,那么第一次执行开始过了10s后,开始第二次执行
-
@Scheduled(fixedDelay = 10000)
指定间隔的执行任务,从方法执行完成开始计时 -
假设方法执行5s,那么第一次执行完成过了10s后,开始第二次执行
-
cron表达式,计划执行的表达式,把六个位置用空格分隔,指代不同单位的时间,执行的规律
- 秒、分钟、小时、日期、月份、星期、(年,可选)
java
// 配置定时执行的注解 支持cron表达式
// 每分钟执行一次 更改可参考cron表达式生成网站
@Scheduled(cron = "0 0/1 * * * ?")
public void updateData() {
System.out.println("更新数据");
saveData();
}
3.展示数据Echarts
是由百度前端技术部开发,基于js的数据可视化图表库。
https://echarts.apache.org/examples/zh/index.html#chart-type-line
分析图形展示的数据来源,然后请求数据后转化成我们需要的格式,传递给页面,通过Echarts渲染出来。
3.1 折线图
3.1.1 分析的请求地址
https://view.inews.qq.com/g2/getOnsInfo?name=disease_other
可以获得json格式的数据,数据的key是chinaDayList
3.1.2 模拟请求
HttpClient使用,应用最广泛的处理http请求的工具。
```xml
java
public static String doGet(String urlStr) {
// 提供了 闭合的httpclient对象
CloseableHttpClient httpClient = null;
// 也提供了 闭合的响应对象
CloseableHttpResponse response = null;
String result = null;
try {
// 使用默认创建方式
httpClient = HttpClients.createDefault();
// 创建一个get请求 传入url
HttpGet httpGet = new HttpGet(urlStr);
// 设置请求头的方式
httpGet.addHeader("Accept", "application/json");
// 设置请求参数 连接时间、数据读取时间(socketTimeOut)等 单位是ms
// ConnectionRequestTimeout 指从共享连接池中取出连接的超时时间
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(35000)
.setConnectionRequestTimeout(35000)
.setSocketTimeout(60000)
.build();
// 设置配置参数
httpGet.setConfig(requestConfig);
// 执行请求
response = httpClient.execute(httpGet);
// 从返回对象中获取返回数据
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity);
}catch (Exception e){
e.printStackTrace();
}
return result;
}
3.1.3 解析出数据
java
import com.duing.bean.GraphBean;
import com.duing.util.HttpClientUtil;
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class GraphHandler {
public static String urlStr = "https://view.inews.qq.com/g2/getOnsInfo?name=disease_other";
public static List<GraphBean> getGraphData() {
List<GraphBean> result = new ArrayList<>();
String str = HttpClientUtil.doGet(urlStr);
Gson gson = new Gson();
Map map = gson.fromJson(str, Map.class);
String subStr = (String) map.get("data");
Map subMap = gson.fromJson(subStr, Map.class);
ArrayList list = (ArrayList) subMap.get("chinaDayList");
for (int i = 0; i < list.size(); i++) {
Map tmp = (Map)list.get(i);
String date = (String)tmp.get("date");
double nowConfirm = (Double)tmp.get("nowConfirm");
GraphBean graphBean = new GraphBean(date,(int)nowConfirm);
result.add(graphBean);
}
return result;
}
}
3.1.4 数据结构
java
@Data
@AllArgsConstructor
public class GraphBean {
private String date;
private int nowConfirm;
}
3.1.5 返回给页面渲染、
java
@GetMapping("/graph")
public String graph(Model model) {
List<GraphBean> list = GraphHandler.getGraphData();
// 进一步改造数据格式
// 因为前端需要的数据是 x轴所有数据的数组和y轴所有数据的数组
ArrayList<String> dateList = new ArrayList<>();
ArrayList<Integer> nowConfirmList = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
GraphBean graphBean = list.get(i);
dateList.add(graphBean.getDate());
nowConfirmList.add(graphBean.getNowConfirm());
}
model.addAttribute("dateList", new Gson().toJson(dateList));
model.addAttribute("nowConfirmList", new Gson().toJson(nowConfirmList));
return "graph";
}
```html
```
Echars教程地址: 教程地址
准备dom -> 通过js渲染数据 -> 使用[[${ sth }]] 接收服务端数据 -> 使用JSON.parse()解析json字符串 -> 获得渲染结果
3.2 折线图2
相关逻辑在 GraphAddBean 对应的代码中:处理数据 -> 转化格式 -> 返回数据给echarts渲染
3.2.1 GraphHandler
java
public static List<GraphAddBean> getGraphAddData(String str) {
List<GraphAddBean> result = new ArrayList<>();
Gson gson = new Gson();
Map map = gson.fromJson(str, Map.class);
String subStr = (String) map.get("data");
Map subMap = gson.fromJson(subStr, Map.class);
ArrayList list = (ArrayList) subMap.get("chinaDayAddList");
for (int i = 0; i < list.size(); i++) {
Map tmp = (Map) list.get(i);
String date = (String) tmp.get("date");
double addConfirm = (Double) tmp.get("confirm");
double addSuspect = (Double) tmp.get("suspect");
GraphAddBean graphAddBean = new GraphAddBean(date, (int) addConfirm, (int) addSuspect);
result.add(graphAddBean);
}
return result;
}
3.2.2 DataController
java
@GetMapping("/graphAdd")
public String graphAdd(Model model) {
List<GraphAddBean> list = GraphHandler.getGraphAddData();
ArrayList<String> dateList = new ArrayList<>();
ArrayList<Integer> addConfirmList = new ArrayList<>();
ArrayList<Integer> addSuspectList = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
GraphAddBean graphAddBean = list.get(i);
dateList.add(graphAddBean.getDate());
addConfirmList.add(graphAddBean.getAddConfirm());
addSuspectList.add(graphAddBean.getAddSuspect());
}
model.addAttribute("dateList", new Gson().toJson(dateList));
model.addAttribute("addConfirmList", new Gson().toJson(addConfirmList));
model.addAttribute("addSuspectList", new Gson().toJson(addSuspectList));
return "graphAdd";
}
3.2.3 HTML
增加折线时,主要在legend和series中增加对应元素。
```html
```
3.3 柱状图
先分析数据的来源 -> 经过对数据的处理和计算 -> 发送给前端组件进行渲染
对应在GraphColumnarBean相关的逻辑中,特别之处在于拿到数据之后需要排序。
java
@Data
@AllArgsConstructor
public class GraphColumnarBean implements Comparable<GraphColumnarBean> {
private String area;
private int fromAbroad;
@Override
public int compareTo(GraphColumnarBean o) {
return o.getFromAbroad() - this.getFromAbroad();
}
}
排序之后将前十的数据返回:
java
@GetMapping("/graphColumnar")
public String graphColumnar(Model model) {
List<GraphColumnarBean> list = GraphHandler.getGraphColumnarData();
Collections.sort(list);
ArrayList<String> nameList = new ArrayList<>();
ArrayList<Integer> fromAbroadList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
GraphColumnarBean bean = list.get(i);
nameList.add(bean.getArea());
fromAbroadList.add(bean.getFromAbroad());
}
model.addAttribute("nameList", new Gson().toJson(nameList));
model.addAttribute("fromAbroadList", new Gson().toJson(fromAbroadList));
return "graphColumnar";
}
柱状图的数据示例:
java
// 指定图表的配置项和数据
var option = {
title: { // 标题组件
text: '境外输入省市TOP10'
},
tooltip: { // 提示框组件
trigger: 'axis'
},
xAxis: {
// 转化为json对象
data: JSON.parse(nameStr)
},
yAxis: {
type: 'value'
},
series: [
{
name: '境外输入',
type: 'bar',
barWidth: '60%',
data: JSON.parse(fromAbroadStr)
}
]
};
3.4 饼状图
对应在GraphPieBean相关的逻辑中
graphPie.html
javascript
// 指定图表的配置项和数据
var option = {
title: { // 标题组件
text: '全国现有确诊构成'
},
tooltip: { // 提示框组件
trigger: 'axis'
},
series: [
{
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
data: JSON.parse(str)
}
]
};
3.5 中国地图
引入新的js【china.js】,数据来源已存储到表格中。
map.html
```html
```
4.国际化
是对thymeleaf中消息表达式的一种应用, #{} , 提供的是对配置文件中信息的读取。
4.1 使用浏览器识别语种
在resources目录下,创建i18n文件夹,再继续创建 *.properties文件。
设置其中的key和value(注意:此时的编码格式需要在idea的设置中确认)
c++
list.title=渡一出品:疫情最新动态-D
list.h2=国内疫情情况如下-D
list.table.name1=地区-D
list.table.name2=现有确诊-D
list.table.name3=累计确诊-D
list.table.name4=治愈-D
list.table.name5=死亡-D
创建其他语种对应的配置文件,如 *_en_US.properties 和 *_zh_CN.properties
在html中更改对key值的引用方式,使用消息表达式:
```html
国内疫情情况如下
.... ```
让spring找到国际化文件对应的位置,在application.properties中:
java
spring.messages.basename=i18n.list
验证方式:通过更改浏览器中 【设置】 -> 【高级】 -> 【语言】 -> 【找到英语(美国)】,可以通过置顶,切换中英文显示。
本质原因是,因为请求的请求头中,会设置不同的Accept-Language的值。
4.2 自定义切换语种
使用spring提供的国际化使用类 LocaleResolver
页面中增加按钮
自定义LocaleResolver类的实现
java
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
public class MyLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
String lan = httpServletRequest.getParameter("lan");
Locale locale = Locale.getDefault();
if (!StringUtils.isEmpty(lan)) {
String[] split = lan.split("_");
locale = new Locale(split[0], split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) { }
}
注入spring
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
@Configuration
public class MyConfig {
@Bean
public LocaleResolver localeResolver() {
return new MyLocaleResolver();
}
}
验证
此时切换按钮时,可以看到不同语种的显示
5.订阅数据
5.1 邮件
java提供的原生的工具,设定的邮件发送和接收流程:
【协议】 SMTP = Simple Mail Transfer Protocol 简单邮件传输协议
在邮件发送时主要会使用到的协议,服务器地址形如:smtp.xxxx.com
如果从qq邮箱,发送邮件到126邮箱, 使用的前提是,确认qq邮箱中【设置】 ->【账户】 -> 【SMTP服务】是开启的状态 ->【获取授权码】
xml
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
java
// 从qq邮箱 发送邮件 到126邮箱
public static void send() throws Exception{
// 1) 通过配置构成邮件的会话
Properties prop = new Properties();
// 配置协议和服务器地址
prop.setProperty("mail.transport.protocol","smtp");
prop.setProperty("mail.smtp.host","smtp.qq.com");
prop.setProperty("mail.smtp.auth","true");
String port = "465";
prop.setProperty("mail.smtp.port",port);
prop.setProperty("mail.smtp.socketFactory.class","javax.net.ssl.SSLSocketFactory");
prop.setProperty("mail.smtp.socketFactory.fallback","false");
prop.setProperty("mail.smtp.socketFactory.port",port);
// 2) 创建会话
Session session = Session.getInstance(prop);
// 3) 创建一封邮件
MimeMessage message = new MimeMessage(session);
String sendMail = "2491638831@qq.com";
String Recipients = "lanluo_bingzi@126.com";
message.setFrom(new InternetAddress(sendMail,"语晴","UTF-8"));
// MimeMessage.RecipientType.CC 抄送 MimeMessage.RecipientType.BCC 密送
message.setRecipient(MimeMessage.RecipientType.TO , new InternetAddress(Recipients,"语晴","UTF-8"));
// 标题 正文 发件时间
message.setSubject("来自语晴的问候","UTF-8");
message.setContent("不要给我发邮件哦","text/html;charset=UTF-8");
message.setSentDate(new Date());
// 可以保存为 *.eml的文件格式
message.saveChanges();
// 4) 获取邮件传输对象 建立连接 并发送
Transport transport = session.getTransport();
String accout = "2491638831@qq.com";
String password = "*************";
transport.connect(accout,password);
transport.sendMessage(message,message.getAllRecipients());
transport.close();
}
springboot中整合
1) 引入依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
2) 参数配置 application.properties
java
spring.mail.username=2491638831@qq.com
spring.mail.password=*********
spring.mail.host=smtp.qq.com
spring.mail.properties.mail.smtp.ssl.enable=true
3) 编写逻辑
java
@Component
public class MailHandler {
@Autowired
private JavaMailSender mailSender;
public void send() {
System.out.println("执行邮件发送逻辑");
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setSubject("来自渡一的问候");
mailMessage.setText("不要不给阿拓老师发邮件");
mailMessage.setTo("lanluo_bingzi@126.com");
mailMessage.setFrom("2491638831@qq.com");
mailSender.send(mailMessage);
}
}
4) 改造成模板引擎渲染的html效果
注意: 要更改为自己的邮箱和密码
5.2 异步任务
如果部署多台服务器,如何保障邮件只发送一次?
消息中间件 ,可以做到发送一条消息让所有服务器都接收,也可以做到发送一条消息,只交给某一台服务器接收(重要特性)。
为了符合消息中间件的等待时间,需要先返回消息处理的结果,再进行具体的逻辑,此时使用异步任务。
使用方式 :
-
先在主程序入口类上,打开相应的开关 @EnableAsync
-
在需要异步执行的方法上添加注解 @Async
6.常用功能
6.1 登录
登录页面编写 login.html,登录的校验逻辑
```java @Controller public class LoginControlle
参考文献
- 微博疫情专题文本的情感分析及可视化(厦门大学·吴萍)
- 新冠疫情舆情信息分析系统的设计与实现(华中科技大学·胡永辉)
- 新冠疫情舆情信息分析系统的设计与实现(华中科技大学·胡永辉)
- 分布式智能网络爬虫的设计与实现(中国科学院大学(工程管理与信息技术学院)·何国正)
- 基于J2EE的网络舆情分析系统的设计与实现(南京大学·李伟)
- 基于新浪微博数据的处理与用户行为分析(北京交通大学·王鲁飞)
- 网络流量统计分析系统(吉林大学·石景龙)
- 社交网络数据提取与分析(北京邮电大学·任毅)
- 基于网络爬虫的排行榜系统设计与实现(北京邮电大学·刘全伟)
- 基于深度学习的微博短文本情感倾向分析(湘潭大学·李维森)
- 基于网络爬虫的信息采集分类系统设计与实现(厦门大学·周茜)
- 基于hadoop的生猪行业网络舆情监控分析系统的设计与实现(华南农业大学·徐富健)
- 社交网络数据提取与分析(北京邮电大学·任毅)
- 互联网舆情监控系统的设计与实现(湖南师范大学·夏岩)
- 数据可视化技术及其在疫情防控中的应用研究(武汉轻工大学·蒋迎香)
本文内容包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主题。发布者:毕业设计客栈 ,原文地址:https://bishedaima.com/yuanma/35510.html