JSP企业快信系统的设计与实现参考论文(论文 + 源码)

【免费】JSP企业快信系统.zip资源-CSDN文库icon-default.png?t=N7T8https://download.csdn.net/download/JW_559/89277688

JSP企业快信系统的设计与实现

摘 要

计算机网络的出现到现在已经经历了翻天覆地的重大改变。因特网也从最早的供科学家交流心得的简单的文本浏览器发展成为了商务和信息的中心。到了今天,互联网已经成为了大量应用的首选平台,人们已经渐渐习惯了网络交易,渐渐对网络产生了依赖。公司会议、机票预定、酒店预定、公司之间货物订单的下达等等工作都可以通过网络快速的完成。网络已经渗透到了人们生活中的方方面面,甚至已经延伸至人们日常的衣食住行各个领域。本项目就是在此背景下设计的企业快信系统。

本系统在开发中,采用了 MYSQL 数据库,同时使用到了 Java Swing、短信猫组件、Java MailAPI 等相关技术。在进行详细设计之前,根据总体设计的结构,确定每部分功能的解决方案,并完成相关技术的可行性分析以及技术原型的实现。在该系统中,采用数据服务器,和客户机相结合形成 B/S 结构,由相关人员或系统管理员执行如系统的备份、恢复、修改等重要操作,从而用来提高系统的安全性,并且降低了了黑客通过 Web 入侵来获取以及改变系统中重要数据信息的可能性。同时,采用 Web 客户机架构 B/S 三层结构,Web 客户机可通过 Internet 或专线连接应用服务器,向其发送指令,从而获取服务。这样做的优点是用浏览器便可进行,使用起来方便快捷,为客户提供了很大的便利。而对于记录管理,系统维护功能而言,主要是对记录信息进行处理,即对数据库信息进行添加,查询,导入和导出操作,这部分功能涉及的主要技术为通过 java连接 MYSQL 数据库,并通过 Java 代码完成对表内信息的查询和添加操作。

本文首先对企业快信的开发进行了较深入的研究,然后对短信发送与邮件发送原理进行了介绍,接下来对系统的概要设计、功能模块、数据库设计,以及名片夹管理功能与邮件发送功能的具体实现作了细致阐述,最后是系统效果的展示。企业快信系统是一个集短信与邮件为一体的移动商务应用系统。是针对企业内部II及外部不同需求和应用方面,而专门定制开发的系统软件。它完全集成了企业的业务推广、客情沟通、内部管理等应用功能。企业快信的作用是帮助企业解决企业内部、企业与外部沟通难、信息不能及时传播等问题。为此,系统提供邮件群发、短信群发、人员档案、信息的管理等功能。系统是短信猫与邮件在企业商务应用中的典型实例,因此必然受到众多企业的青睐,成为企业通信的最佳选择。

关键词:短信发送;邮件发送;企业快信


The Design and Implementation of Enterprise’s Express Letter System

Abstract

Computer network has undergone a great change.The internet has also developed intoa business and information center from the earliest.The company eeting,airlinereservation,hotel reservation, release the order of goods between the companies and so on,these all can becompleted through the network quikly.Internet has penetrated into every aspect of people’s life, even extending to the basic necessities of life in all areas of people’s daily life, The enterprise’s express letter system is designed in this context.

The system development uses MYSQL database, uses Java Swing, GSM Modem, Java mail API and other Technology. Before the detailed design of the structure of the overall design to determine the solution of some of the features, and complete the feasibility analysis and prototype implementation of the related technologies. In this system, data server and client combine to form the C/S structure, performed by the financial staff or system managers, such as system backup, restore, and modify the amount of important operating to improve the security of the system, reduce hacker by Web Intrusion to access and change the possibility of important information. The same time, the use of the Web client organizations into the B / S three-tier Web client can be connected through the Internet or green application server, send commands, and thus access to services. The advantage is you can operate from a browser, easy to use, fast and efficient, convenient to the customer with the greatest convenience. For records management, system maintenance functions, record information that the database information to add, query, import and export operations, some of the features involved in technology to through VC6 connect the MYSQL database, and Java code to query and add operations on the information in the table.

In this paper, we research the development of enterprise’s express letter system at first,and then introduce the principles of sending SMS and mails, After that, we made a elaboration of the summary of the system design, function modules, database design,business card folder management capabilities, as well as of the e-mail function’s concreterealization.Finally, we show the system’s effect.The enterprise’s express letter system is a mobile business of application systemwhich sets SMS and E-mail as a whole .The system software is specificallycustom-developed for internal and external needs and applications. It is fully integrated enterprise business promotion, customer intelligence, communication, internal management applications. The enterprise’s express letter system of the role is to help businesses solve internal, corporate and external communication difficult, not timely issemination of information and other issues. To this end, the system provides functions as java mail, BSwing , personnel files, information management and so on. The system is a typical example of the GSM Modem and e-mail in the enterprise business applications, so it will be subject to the favor of many enterprises, the best choice for business communications.

Key words:Java Mail;BSwing;Express Letter

1  绪论

1.1  开发背景

在企业信息化的今天,效率决定成败,企业内、外部沟通的及时性将直接影响企业的运作效率。现在多数企业的办公自动化系统(即OA)的信息传递仅限于计算机内部网络,如果用户不在线,将无法知道是否有新的工作或紧急通知,为了确认是否有待办工作,不得不经常去访问OA,检索是否有新任务,而事实上这种检索的结果经常是徒劳。这样一来,不仅造成了机器资源的浪费,也造成了人力资源的浪费。因此急需一套成型的企业快信系统解决上述问题。

1.2  国内外发展概况

短消息服务市场近来如此火爆,让许多人始料未及,预示着短消息的巨大市场空间。短消息(Short Message Service)是手机通过移动网进行个人简易数据通信的一种方式,具有覆盖范围广、双向寻呼、使用经济、可缓存处理等优点,满足了人们爆炸性增长的信息需求,使人们可以以低廉的价格、便捷的方式,随时随地得到充满个性化的信息,是无线通信在 20 世纪末所做的一次重要飞跃。这使得移动网络不仅可以传送音频,也可以传送数据,而数据传输是互联网技术的根本。

在国外,短消息业务占移动运营商收入的很大比例。国内移动通信在保持较高增长速度的同时,数据业务正在成为运营商的重要收入来源,几大电信公司不约而同地把目光盯住了手机短信。据统计,从 2000 年第四季度开始,全国短消息业务量以每月几千万条的数量突然激增,已经成为一个不容忽视的巨大的市场!

而随着中国移动通信用户的不断增长,如何最大程度地利用现有网络,挖掘网络潜力,方便灵活地开展增值服务,拓展网络应用服务领域,满足用户日益增长的服务需求成为网络运营商所要考虑的重点,因此,短消息增值服务已成为吸引用户和增加收入的有效手段。开展增值服务不仅可以直接增加业务收入,而且通过提供不同种类的服务,可以吸引更多的顾客群体,对于拓展用户、提高市场应用效率具有非常重要的意义,潜在的收益更为巨大。

1.3  研究目的和意义

本课题通过对企业快信系统的开发主要达到以下两个目的:

1)企业快信系统面对成千上万用户的连接以及同时的数据库请求,对数据库访问的效率和安全成了必须解决的问题。通过对JAVA 平台下数据库存取机制的深入研究,找出一条效率,性能与安全平衡的道路。

2)Web 开发的实例,对如何把 B/S 与 C/S 相结合进行了研究,并对面向对象对多层结构的支持进行了详细的分析。

企业快信主要是高效和安全的对企业提供企业级快信和服务,基于JAVA的多层结构来进行 web 开发必然是今后的主流,并且由于同时面对多用户及多连接,对数据库存取效率及性能,安全都有很高要求,因此,文中对数据库的高效安全的存取进行了深入研究并且获得了有效的进展。通过对其具体应用进行研究对相关开发人员和以后的软件开发及应用都有十分重要的意义。

1.4  研究主要内容

在一个提供企业级短信的系统的设计与实现中,把 C/S 和 B/S 架构根据实际情况进行结合,着重对数据库存取中的各种机制进行了深入地研究并且根据系统自身特点进行了选择和加强,采用了MySQL 数据供应器池化,并使用 Windows7 自带的性能监视器来监视链接池,最后讨论了设置链接池大小的各种问题,选择合适的大小,实现高效与安全有效的结合。并且结合 web 开发的实例,对面向对象对多层结构的支持进行了详细的分析。

基于JAVA的 B/S 架构来进行 web 开发必然是今后的主流,并且由于同时面对多用户及多连接,对数据库存取效率及性能,安全都有很高要求,因此,通过对其具体应用进行研究对相关开发人员和以后的软件开发及应用都有十分重要的意义。


2  系统分析

2.1  需求分析

企业快信的作用是帮助企业解决企业内部、企业与外部沟通难、信息不能及时传播等问题。为此,企业快信系统需要提供邮件群发、短信群发等功能。通过对多数企业日常业务的考察、分析,并结合短信及邮件自身的特点,得出本系统要求具有以下功能。

þ 用于管理客户和员工信息的名片夹管理功能。

þ 用于对常用短语及其类别进行管理的信息库管理功能。

þ 短信群发功能。

þ 邮件群发功能。

þ 发送邮件附件的功能。

2.2  可行性研究

开发任何一个基于计算机的系统,都会受到时间和资源上的限制。因此,在接受任何一个项目开发任务之前,必须根据客户可能提供的时间和资源条件进行可行性分析,以减少项目开发风险,避免人力、物力和财力的浪费。可行性分析与风险分析在很多方面是相互关联的,项目风险越大,开发高质量的软件的可行性就越小。

2.2.1  经济可行性

采用短信作为企业的移动通信手段,将给企业对内、对外进行信息传递与沟通带来革命性的变化,从而使得移动办公、客户服务、员工沟通等运作效率显著提升,而成本则显著下降。值得说明的是,虽然短信有以上诸多优点,但它还是有一定的不足,例如信息内容单一和受到字数限制等。为解决这一问题,在企业快信中提供了邮件群发功能。通过邮件进行沟通也是目前比较流行的方式,它也具备实用、方便和廉价等优点。

2.2.2  技术可行性

开发一个企业快信系统,涉及到的技术问题不会太多,主要用到的技术就是使用短信猫和Java Mail组件来实现收发短信和群发邮件等功能。Java Mail 组件是Sun 公司发布的一种用于读取、编写和发送电子邮件的包,利用它可以方便地实现邮件群发。

2.3  开发环境

在开发企业快信时,需要具备下面的软件环境。

服务器端:

þ 操作系统:Windows 7。

þ Java 开发包:JDK 1.5 以上。

þ Web服务器:Tomcat6.0。

þ Java Mail 开发包:Java Mail 1.4。

þ 数据库:MYSQL。

þ 浏览器:IE 10.0。

þ 分辨率:最佳效果为1024×768 像素。

客户端:

þ 浏览器:IE 10.0。

þ 分辨率:最佳效果为1024×768 像素。

由于本系统中需要使用Java Mail 组件,下面将详细介绍如何配置及Java Mail 的开发环境。

由于目前Java Mail 还没有被加在标准的Java 开发工具中,所以在使用前必须另外下载Java MailAPI,以及Sun 公司的JAFJavaBeans Activation Framework),Java Mail 的运行必须信赖于JAF 的支持。

þ 下载并构建Java Mail API

Java Mail API 是发送和接收E-mail 的核心API。需自行下载后解压缩到硬盘上,并在系统的环境变量CLASSPATH 中指定activation.jar 文件的放置路径。

þ 下载并构建JAF

目前Java Mail API 的所有版本都需要JAFJavaBeans Activation Framework)的支持。JAF 为输入的任意数据块提供了支持,并能相应地对其进行处理。下载后解压缩到硬盘上,并在系统的环境变量CLASSPATH 中指定activation.jar 文件的放置路径。

如果不想更改环境变量,也可以把activation.jar 添加到工程的构建路径中。


3  系统总体设计

3.1  系统目标

根据前面所作的需求分析及用户的需求可知,企业快信属于小型的企业通信软件,在系统实施后,应达到以下目标。

þ 界面设计友好、美观。

þ 操作灵活、方便。

þ 提供功能强大的信息库管理,方便用户进行短信息的编写。

þ 提供邮件群发功能,提高工作效率。

þ 在发送短信时,可以直接从现有信息库中获取信息内容。

þ 对用户输入的数据,进行严格的数据检验,尽可能地避免人为错误。

þ 数据存储安全、可靠。

3.2  系统功能结构

根据企业快信的特点,可以将其分为名片夹管理、信息库管理、短信群发、邮件群发、系统参数设置、系统设置6个部分,其中各个部分及其包括的具体功能模块如图3-1 所示。

图3-1 系统功能结构

3.3  业务流程图

企业快信的系统流程如图3-2 所示。

图3-2 系统流程图

3.4  系统预览

企业快信由多个程序页面组成,下面仅列出几个典型界面。

系统登录页面如图3-3所示,该页面用于实现管理员登录功能;主页如图3-4所示,该页面用于实现显示系统导航、操作业务流程和版权信息等功能。

图3-3 系统登录页面

图3-4 主 页

发送短信页面如图3-5所示,该页面用于实现将短信息同时发给多个接受者的功能;同时,为方便用户还提供了从客户及员工列表中选择接收者及从信息库中选择指定信息的功能。

图3-5 发送短信页面

邮件群发页面如图3-6所示,该页面用于实现将邮件同时发给多个接受者的功能;同时,为方便用户还提供了从客户及员工列表中选择接收者的功能。

图3-6 邮件群发

3.5  文件夹组织结构

在编写代码之前,需要把系统中可能用到的文件夹先创建出来(例如创建一个名为img 的文件夹,用来保存程序中使用的效果图片),这样不但方便以后的开发工作,也可以规范软件的整体架构。本人在开发企业快信时,设计了如图3-7 所示的文件夹架构。在开发时,只需要将所创建的文件保存在相应的文件夹中就可以了。

图3-7 企业快信文件夹组织结构


4  系统详细设计

4.1  数据库设计

4.1.1  数据库分析

由于本系统是一个小型实用的信息群发系统,提供了名片夹和信息库的功能,用户可以将常用的人员保存到名片夹中,将常用的短语保存到信息库中,以方便使用。基于这个特点以及语言特点,本系统将采用MySQL 数据库作为底层数据库,以方便用户使用本系统。

4.1.2  数据库概念设计

根据以上对系统所作的需求分析和系统设计,规划出本系统中使用的数据库实体分别为类型实体、档案实体、常用短语实体、管理员实体。下面将给出几个关键实体的E-R 图。

þ 档案实体

档案实体包括编号、客户名称、地址、邮政编码、所属区域、手机号码、邮件地址、银行账户、开户银行和联系人属性,档案实体的E-R 图如图4-1 所示

图4-1 档案实体E-R

þ 短信实体

短信实体包括编号、收信人的手机号码、短信内容、发信人和发送时间属性,短信实体的E-R 图如图4-2 所示。

þ 常用短语

常用短语实体包括编号、类型和内容,常用短语实体的E-R 图如图4-3 所示。

4-2 短信实体E-R 4-3 类型实体E-R

4.1.3  数据库逻辑结构设计

在数据库概念设计中已经分析了档案实体、常用短语实体和类型实体,这些实体对象是数据表结的基本模型,最终的数据模型都要实施到数据库中,形成整体的数据结构。图4-4 为通过PowerDesigner创建完成的数据库模

4-4 数据库模型图

tb_customer 的表结构如表4-1 所示。

表4-1 tb_customer 的表结构

字 段 名

数 据 类 型

是 否 为 空

是 否 主 键

默 认 值

描  述

ID

int

No

Yes

ID(自动编号)

name

varchar(50)

No

NULL

客户名称

address

varchar(100)

No

NULL

地址

postcode

varchar(6)

No

NULL

邮政编码

area

varchar(20)

Yes

NULL

所属区域

mobileTel

avarchar(15)

No

NULL

手机号码

email

varchar(100)

No

NULL

邮件地址

bankNo

varchar(30)

Yes

NULL

银行帐号

bankName

varchar(20)

Yes

NULL

开户银行

linkName

varchar(10)

No

NULL

联系人

tb_shortLetter 的表结构如表4-2 所示。

表4-2 tb_shortLetter 的表结构

字 段 名

数 据 类 型

是 否 为 空

是 否 主 键

默 认 值

描  述

ID

int

No

Yes

ID(自动编号)

toMan

varchar(200)

No

NULL

发信人手机号码

content

varchar(500)

No

NULL

短信内容

fromMan

varchar(30)

No

NULL

发信人

sendTime

datetime

No

getdate()

发送时间

4.2  公共模块设计

在开发过程中,经常会用到一些公共模块,如数据库连接及操作的类、字符串处理的类及Struts配置等,因此,在开发系统前首先需要设计这些公共模块。下面将具体介绍企业快信系统中所需要的公共模块的设计过程。

4.2.1  数据库连接及操作类的编写

数据库连接及操作类通常包括连接数据库的方法getConnection()、执行查询语句的方法executeQuery()、执行更新操作的方法executeUpdate()、关闭数据库连接的方法close().下面将详细介绍如何编写企业快信系统中的数据库连接及操作的类ConnDB。

(1)定义ConnDB类

定义用于进行数据库连接及操作的类ConnDB,并将其保存到com.wgh.core包中,同时定义该类中所需的全局变量及构造方法。代码如下:

public class ConnDB {

public Connection conn = null; // 声明Connection对象的实例

public Statement stmt = null; // 声明Statement对象的实例

public ResultSet rs = null; // 声明ResultSet对象的实例

private static String propFileName = "/com/connDB.properties"; // 指定资源文件保存的位置

private static Properties prop = new Properties(); // 创建并实例化Properties对象实例

private static String dbClassName = " ";//定义保存数据库驱动的变量

private static String dbUrl =  " ";

private static String dbUser = "sa";

private static String dbPwd = "";

public ConnDB() { //定义构造方法

try { //捕捉异常

//将Properties文件读取到InputStream对象中

InputStream in = getClass().getResourceAsStream(propFileName);

prop.load(in); // 通过输入流对象加载Properties文件

dbClassName = prop.getProperty("DB_CLASS_NAME");//获取数据库驱动

dbUrl = prop.getProperty("DB_URL", dbUrl); //获取URL

dbUser = prop.getProperty("DB_USER", dbUser); //获取登录用户

dbPwd = prop.getProperty("DB_PWD", dbPwd); //获取密码

} catch (Exception e) {

e.printStackTrace(); // 输出异常信息

}

}

}

(2)将数据保存到资源文件中

为了方便程序移植,将数据库连接所需信息保存到properties文件中,并将该文件保存在com包中。connDB.properties文件的内容如下:

DB_CLASS_NAME=com.mysql.jdbc.Driver

DB_URL=jdbc:mysql://127.0.0.1:3306/db_expressLetter

DB_USER=sa

DB_PWD=

(3)创建数据库连接

创建连接数据库的方法getConnection(),该方法返回connection对象的一个实例。getConnection()方法的实现代码如下:

public static Connection getConnection() {

Connection conn = null;

try {

Class.forName(dbClassName).newInstance();

conn = DriverManager.getConnection(dbUrl, dbUser, dbPwd);

} catch (Exception ee) {

ee.printStackTrace();

}

if (conn == null) {

System.err.println("警告: DbConnectionManager.getConnection() 获得数据库链接失败.\r\n\r\n链接类型:"+ dbClassName+ "\r\n链接位置:" + dbUrl+ "\r\n用户/密码"+ dbUser + "/" + dbPwd);

}

return conn;

}

(4)创建查询方法

创建执行查询语句的方法exccuteQuery(),返回值为Resultset结果集。executeQuery()方法的代码如下:

public ResultSet executeQuery(String sql) {

try { // 捕捉异常

conn = getConnection(); // 调用getConnection()方法构造Connection对象的一个实例conn

stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,

ResultSet.CONCUR_READ_ONLY);

rs = stmt.executeQuery(sql);

} catch (SQLException ex) {

System.err.println(ex.getMessage()); // 输出异常信息

}

return rs; // 返回结果集对象

}

(5)创建更新操作方法

创建执行更新操作的方法executeUpdate(),返回值为int型的整数,代表更新的行数。executeUpdate()方法的代码如下:

public int executeUpdate(String sql) {

int result = 0; // 定义保存返回值的变量

try { // 捕捉异常

conn = getConnection(); // 调用getConnection()方法构造Connection对象的一个实例conn

stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,

ResultSet.CONCUR_READ_ONLY);

result = stmt.executeUpdate(sql); // 执行更新操作

} catch (SQLException ex) {

result = 0; // 将保存返回值的变量赋值为0

}

return result; // 返回保存返回值的变量

}

(6)关闭数据库连接

创建关闭数据库连接的方法close()close()方法的代码如下:

public void close() {

try { // 捕捉异常

if (rs != null) { // 当ResultSet对象的实例rs不为空时

rs.close(); // 关闭ResultSet对象

}

if (stmt != null) { // 当Statement对象的实例stmt不为空时

stmt.close(); // 关闭Statement对象

}

if (conn != null) { // 当Connection对象的实例conn不为空时

conn.close(); // 关闭Connection对象

}

} catch (Exception e) {

e.printStackTrace(System.err); // 输出异常信息

}

}

4.2.2  字符串处理类的编写

字符串处理类主要用于解决程序中经常出现的有关字符串处理的问题,包括将数据库中及页面中有中文问题的字符串进行正确地显示和对字符串中的空值进行处理的方法。其代码如下:

public class ChStr {

    public static String toChinese(String strvalue) {

    try {

        if (strvalue == null) {

            return "";

        } else {

            strvalue = new String(strvalue.getBytes("ISO8859_1"), "GBK").trim();

            return strvalue;

        }

    } catch (Exception e) {

        return "";

    }

}

//处理字符串中的空值

 public static final String nullToString(String v, String toV) {

     if (v == null || "".equals(v)) {

         v = toV;

     }

     return v;

}

4.2.3  配置Struts

Struts框架需要通过一个专门的配置文件来控制,就是struts-config.xml。那么网站是怎么找到这个Struts的配置文件的呢?只要在web.xml中配置一下就可以了。具体实现代码如下:

  <servlet>

    <servlet-name>action</servlet-name>

    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>

  </servlet>

  <servlet>

    <servlet-name>action_tmp</servlet-name>

    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>

    <init-param>

      <param-name>config</param-name>

      <param-value>/WEB-INF/struts-config.xml</param-value>

    </init-param>

  </servlet>

  <servlet-mapping>

    <servlet-name>action</servlet-name>

    <url-pattern>*.do</url-pattern>

  </servlet-mapping>

  <!-- 设置默认文件名称 -->

  <welcome-file-list>

    <welcome-file>login.jsp</welcome-file>

  </welcome-file-list>

在web.xml中配置Struts的配置文件,实际就是一个servlet的配置,即在配置serylet的config参数中定义struts的配置文件(包括相对路径)及在servlet的URL访问里使用后缀名。接下来的工作就是如何配置struts-config.xml文件。Struts-config.xml文件的关键代码如下:

<?xml version="1.0" encoding="UTF-8"?>

<struts-config>

  <data-sources />

  <form-beans >

    <form-bean name="managerForm" type="com.wgh.actionForm.ManagerForm" />

… //此处省略其他<form-bean>代码

  </form-beans>

  <action-mappings >

  <!-- 管理员 -->

 <action name="managerForm" path="/manager" scope="request" type="com.wgh.action.Manager" validate="true">

      <forward name="managerLoginok" path="/main.jsp" />

      <forward name="managerQuery" path="/manager.jsp" />

      <forward name="managerAdd" path="/manager_ok.jsp?para=1" />

      <forward name="pwdQueryModify" path="/pwd_Modify.jsp" />

      <forward name="managerDel" path="/manager_ok.jsp?para=3" />

      <forward name="modifypwd" path="/main.jsp" />

      <forward name="error" path="/error.jsp" />

    </action>

… //此处省略其他<action >代码

  </action-mappings>

</struts-config>

4.3  主页设计

4.3.1  主页概述

管理员通过系统登录模块的验证后,可以登录到企业快信的系统主页。系统主页主要包括系统导航栏、显示区和版权信息3部分。其中,导航栏中的功能菜单将根据登录管理员的权限进行显示。例如,系统管理员tsoft登录后,将拥有整个系统的全部功能,因为他是超级管理员。系统主页的运行效果如图4-5 所示。

4-5 企业快信主页运行效果

4.3.2  主页技术分析

在实现系统主页时,最关键的就是如何实现导航菜单.本系统中采用的方法是通过Javascript+CSS样式控制<div>标记来实现。其具体实现方法如下:

(1)在要显示导航菜单的位置添加相应的主菜单项。具体代码如下:

<a href="main.jsp">首页</a> |

<a  οnmοuseοver=showmenu(event,cardClip) οnmοuseοut=delayhidemenu() class='navlink' style="CURSOR:hand" >名片夹管理</a> |

<a  οnmοuseοver=showmenu(event,infoLibrary) οnmοuseοut=delayhidemenu() class='navlink' style="CURSOR:hand" >信息库管理</a> |

<a  οnmοuseοver=showmenu(event,shortLetter) οnmοuseοut=delayhidemenu() class='navlink' style="CURSOR:hand" >发送短信</a> |

<a  href="sendMail.do?action=addMail">邮件群发</a> |

<%if(purview.equals("1")){%>

<a  href="sysParameterSet.do?action=parameterQuery" >系统参数设定</a> |

<%}%>

<a οnmοuseοver=showmenu(event,sysSet) οnmοuseοut=delayhidemenu() class='navlink' style="CURSOR:hand">系统设置</a>

| <a href="#" onClick="quit()">退出系统</a>

在Javascript中指定各个子菜单的内容,并根据登录管理员的权限控制要显示的菜单项.关键代码如下:

<script language="javascript">

var cardClip='<table width=56><tr><td id=customer onMouseOver=overbg(customer) onMouseOut=outbg(customer)><a href=customer.do?action=customerQuery>客户管理</a></td></tr>\

<tr><td id=personnel onMouseOver=overbg(personnel) onMouseOut=outbg(personnel)><a href=personnel.do?action=personnelQuery>员工管理</a></td></tr>\

</table>'

var infoLibrary='<table width=86><tr><td id=infoType onMouseOver=overbg(infoType) onMouseOut=outbg(infoType)><a href=infoType.do?action=infoTypeQuery>信息类别管理</a></td></tr>\

<tr><td id=shortInfo onMouseOver=overbg(shortInfo) onMouseOut=outbg(shortInfo)><a href=shortInfo.do?action=shortInfoQuery>常用短语管理</a></td></tr>\

</table>'

<%if(purview.equals("1")){%>

var shortLetter='<table width=86><tr><td id=sendLetter onMouseOver=overbg(sendLetter) onMouseOut=outbg(sendLetter)><a href=sendLetter.do?action=addLetter>发送短信</a></td></tr>\

<tr><td id=historyQ onMouseOver=overbg(historyQ) onMouseOut=outbg(historyQ)><a href=sendLetter.do?action=historyQuery>查看发送日志</a></td></tr>\

</table>'

<%}else{%>

var shortLetter='<table width=56><tr><td id=sendLetter onMouseOver=overbg(sendLetter) onMouseOut=outbg(sendLetter)><a href=sendLetter.do?action=addLetter>发送短信</a></td></tr>\

</table>'

<%}if(purview.equals("1")){%>

var sysSet='<table width=70><tr><td id=manager onMouseOver=overbg(manager) onMouseOut=outbg(manager)><a href=manager.do?action=managerQuery>操作员管理</a></td></tr>\

<tr><td id=changePWD onMouseOver=overbg(changePWD) onMouseOut=outbg(changePWD)><a  href="manager.do?action=queryPWD">更改口令</a></td></tr>\

</table>'

<%}else{%>

var sysSet='<table width=70><tr><td id=changePWD onMouseOver=overbg(changePWD) onMouseOut=outbg(changePWD)><a   href="manager.do?action=queryPWD">更改口令</a></td></tr></table>'

<%}%>

</script>

4.4  名片夹管理模块设计

4.4.1  名片夹管理模块概述

名片夹管理模块主要包括客户信息管理和员工信息管理,其中,客户信息管理包括查看客户列表、添加客户信息、修改客户信息和删除客户信息4个功能:员工信息管理包括查看员工列表、添加员工信息、修改员工信息和删除员工信息4个功能。

4.4.2  名片夹管理模块技术分析

名片夹管理模块主要包括客户管理和员工管理两部分,由于这两部分的买现方法大致相同,所以本节将以客户管理为例介绍名片夹管理模块。在实现客户管理时,需要编写客户管理对应的ActionForm类和Action实现类。下面将详细介绍如何编写客户管理的ActionForm类和创建客户管理的Action实现类。

(1)编写客户管理的ActionForm类

在客户管理中,只涉及到一个数据表,即tb_customer(客户信息表),根据这个数据表可以得出客户管理的ActionForm类。客户管理的ActionForm类的名称为CustomerForm,具体代码如下:

public class CustomerForm extends ActionForm {

private String bankNo; //银行账号

private String area; //所属区域

private String email; //邮箱

private String address; //地址

private String mobileTel; //手机号码

private String name; //客户全称

private int ID; //编号

private String bankName; //开户银行

private String postcode; //邮政编码

private String linkName; //联系人

public String getBankNo() {

return bankNo;

}

public void setBankNo(String bankNo) {

this.bankNo = bankNo;

}

… //此处省略其他控制客户信息的get()和set()方法

}

(2)创建客户管理的Action实现类

客户管理的Action实现类Customer继承了Action类.在该类中,首先需要在该类的构造方法中实例化客户管理的CustomerDAO类(该类用于实现与数据库的交互)。Action实现类的主要方法是execute(),该方法会被自动执行其本身没有具体的事务,是根据通过HttpservletRequest的getParamer()方法获取的action参数值执行相应方法的。客户管理的Action实现类的关键代码如下:

public class Customer extends Action{

    private CustomerDAO customerDAO = null;

    private ChStr chStr=new ChStr();

    public Customer() {

        this.customerDAO = new CustomerDAO();

    }

public ActionForward execute(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response){

       String action = request.getParameter("action");

       System.out.println("获取的查询字符串:" + action);

       if (action == null || "".equals(action)) {

         request.setAttribute("error","您的操作有误!");

          return mapping.findForward("error");

       }else if ("customerQuery".equals(action)) {

            return customerQuery(mapping, form, request,response);

}else if("customerAdd".equals(action)){

 return customerAdd(mapping, form, request,response);

}

else if("customerModify".equals(action)){

            return customerModify(mapping, form, request,response);

        }

request.setAttribute("error", "操作失败!");

return mapping.findForward("error");

}

…… //此处省略了该类中其他方法,这些方法将在后面的具体过程中给出。

}

4.4.3  查看客户信息列表的实现过程

查看客户信息列表使用的数据表:tb_customer

管理员登录后,选择“名片夹管理/客户管理”命令,进入到查看客户列表页面,在该页面中将以列表形式显示全部客户信息,同时提供添加客户信息、修改客户信息、删除客户信息的超链接。查看客户信息列表页面的运行效果如图4-6 所示。

图4-6 客户信息列表页面

在查看客户信息列表的方法customerQuery()中,首先调用CustomerDAO类中的query()方法查询全部客户信息,再将返回的查询结果保存到HttpServletRequest对象的CustomerQuery参数中.查看客户信息列表的方法CustomerQuery()的具体代码如下:

private ActionForward customerQuery(ActionMapping mapping, ActionForm form,

        HttpServletRequest request,HttpServletResponse response) {

        request.setAttribute("customerQuery", customerDAO.query(0));

        return mapping.findForward("customerQuery");

}

查看客户信息列表使用的CustomerDAO类的方法是query()。该方法只有一个用于指定客户ID的参数id(如果记的值为null,则查询全部客户信息),然后将查询结果保存到List集合中并返回该集合的实例。Query()方法的具体代码如下:

public List query(int id) {

     List customerList = new ArrayList();

        CustomerForm cF = null;

        String sql="";

        if(id==0){

            sql = "SELECT * FROM tb_customer";

        }else{

         sql = "SELECT * FROM tb_customer WHERE ID=" +id+ "";

        }

        ResultSet rs = conn.executeQuery(sql);

        try {

            while (rs.next()) {

                cF = new CustomerForm();

                cF.setID(rs.getInt(1));

                cF.setName(rs.getString(2));

                ……//此处省略获取并设置其他属性的代码

                cF.setLinkName(rs.getString(10));

                customerList.add(cF);

            }

        } catch (SQLException ex) {}

        finally{

conn.close();//关闭数据库连接}

        return customerList;

    }

4.4.4  添加客户信息的实现过程

添加客户信息使用的数据表:tb_customer.

管理员登录后,选择“名片夹管理/客户管理”命令,进入到查看客户列表页面。在该页面中,单击“添加客户信息”超链接,进入到添加客户信息页面。添加客户信息页面的运行效果如图4-7 所示。

图4-7 添加客户信息页面

(1)设计添加客户信息页面

添加客户信息页面主要用于收集输入的客户信息及通过自定义的Javascript函数验证输入信息是否合法,该页面中所涉及的表单元素如表4-3 所示。

表4-3 表tb_customer的表结构

名  称

元 素 类 型

重 要 属 性

含义

title

form

action="customer.do?action=customerAdd" method="post" onSubmit="return checkform(form1)

表单

name

text

size=50

客户全称

area

text

size=30

所在区域

address

text

size=60

地址

postcode

text

size=6

邮政编码

linkName

text

size=20

联系人

mobileTel

text

size=30

手机号码

Email

text

size=50

邮箱

bankName

text

size=20

开户银行

bankNo

text

size=30

银行帐号

Submit

submit

value=提交

“提交”按钮

Submit2

reset

value=重置

“重置”按钮

Submit3

button

onClick="window.location.href='customer.do?action=customerQuery'" value="返回"

“返回”按钮

(2)修改客户的Action实现类

在添加客户信息页面中输入合法的客户信息后,单击“提交”按钮,网页会访问一个URL,即customer.do?action=customerAdd从该URL地址中可以知道添加客户信息模块涉及到的action的参数值为customerAdd,也就是当action=customerAdd时,会调用添加客户信息的方法customerAdd()。具体实现代码如下

if("customerAdd".equals(action)){

 return customerAdd(mapping, form, request,response);

}

在添加客户信息的方法customerAdd()首先需要将接收到的表单信息强制转换成ActionForm类型,并用获得指定属性的getXXX()重新设置该属性的setXXX()方法,然后调用customerDAO类中的insert()方法,将添加的客户信息保存到数据表中,并将返回值保存到变量ret中.如果返回值为l,表示信息添加成功,将页面重定向到添加信息成功页面:如果返回值为2,表示该客户信息己经添加,将错误提示信息“该客户信息己经添加!”保存到HttpServletRequest对象的error参数中,然后将页面重定向到错误提示信息页面;否则将错误提示信息“客户信息添加失败里”保存到HttpServletRequest对象的error参数中,并将页面重定向到错误提示页面.添加客户信息的方法customerAdd()的具体代码如下:

private ActionForward customerAdd(ActionMapping mapping, ActionForm form,

          HttpServletRequest request,HttpServletResponse response) {

      CustomerForm customerForm = (CustomerForm) form;

      //此处需要进行中文转码

      customerForm.setName(chStr.toChinese(customerForm.getName()));

      customerForm.setAddress(chStr.toChinese(customerForm.getAddress()));

      customerForm.setArea(chStr.toChinese(customerForm.getArea()));

customerForm.setBankName(chStr.toChinese(customerForm.getBankName()));

customerForm.setLinkName(chStr.toChinese(customerForm.getLinkName()));

      int ret = customerDAO.insert(customerForm);

      System.out.println("返回值ret:"+ret);

      if (ret == 1) {

          return mapping.findForward("customerAdd");

      } else if(ret==2){

          request.setAttribute("error","该客户信息已经添加!");

          return mapping.findForward("error");

      }else {

          request.setAttribute("error","添加客户信息失败!");

          return mapping.findForward("error");

      }

  }

(3)编写添加客户信息的CustomerDAO类的方法

添加客户信息使用的customerDAO类的方法是insert()。在insert()方法中,首先从数据表tb_customer中查询输入的客户全称是否存在,如果存在,将标志变最设置为2,否则将输入的信息保存到客户信息表中,并将返回值赋给标志变量,最后返回标志变量。Insert()方法的具体代码如下:

public int insert(CustomerForm cF) {

      String sql1="SELECT * FROM tb_customer WHERE name='"+cF.getName()+"'";

      ResultSet rs = conn.executeQuery(sql1);

      String sql = "";

      int falg = 0;

          try {

              if (rs.next()) { falg=2;} else {

                  sql = "INSERT INTO tb_customer (id,name,address,area,postcode,mobileTel,email,bankName,bankNo,linkName) values(null,'" + cF.getName() + "','" +cF.getAddress() +"','"+cF.getArea()+"','"+cF.getPostcode()+"','"+cF.getMobileTel()+"','"+ cF.getEmail()+"','"+cF.getBankName()+"','"+cF.getBankNo()+"','"+cF.getLinkName()+"')";

                  falg = conn.executeUpdate(sql);

                  System.out.println("添加客户信息的SQL:" + sql);

                    conn.close();

              }

          } catch (SQLException ex) { falg=0;}

      return falg;

  }

(4)Struts-config.xml文件配置

在struts-config.xml文件中配置添加客户信息所涉及的<forward>元素。代码如下:

<forward name="managerAdd" path="/manager_ok.jsp?para=1" />

4.4.5  删除客户信息的实现过程

在删除客户信息的方法customerDel()中,首先需要将接收到的表单信息强制转换成ActionForm类型,并用获得的记参数的值重新设置该ActionForm的setId()方法,再调用customerDAO类中的delete()方法,删除指定的客户信息,并根据执行结果将页面转到相应页面.删除客户信息的方法customerDel()的具体代码如下:

 private ActionForward customerDel(ActionMapping mapping, ActionForm form,

              HttpServletRequest request, HttpServletResponse response) {

     CustomerForm customerForm = (CustomerForm) form;

     customerForm.setID(Integer.parseInt(request.getParameter("id")));

     int ret = customerDAO.delete(customerForm);

     if (ret != 0) {

         request.setAttribute("error","删除客户信息失败!!");

         return mapping.findForward("error");

     } else { return mapping.findForward("customerDel"); }

 }

删除客户信息使用的CustomerDAO类的方法是delete()。在delete()方法中,将从客户信息表tb_customer中删除符合条件的数据,并返回执行结果。delete()方法的具体代码如下:

public int delete(CustomerForm customerForm) {

int flag=0;

try{

  String sql = "DELETE FROM tb_customer where id=" + customerForm.getID() +"";

    flag = conn.executeUpdate(sql);

}catch(Exception e){

System.out.println("删除客户信息时产生的错误:"+e.getMessage());

    }finally{ conn.close(); //关闭数据库连    }

    return flag;

}

在struts-config.xml文件中配置添加客户信息所涉及的<forward>元素。代码如下:

<forward name="managerDel" path="/manager_ok.jsp?para=3" />

4.5  发送短信模块设计

4.5.1  发送短信模块功能概述

发送短信模块主要包括发送短信、查看发送日志两个功能。这两个功能之间的业务流程如图4-8 所示。

图4-8 业务流程图

发送短信模块是企业快信系统的核心模块之一,操作员可以通过该模块对企业内部的所有或者部分员工,以短信的形式发送企业通知、工资条、具体技术、开会等信息,并且这个信息是群体发送的。

4.5.2  发送短信的实现过程

发送短信使用的数据表:tb_shortLetter、tb_shortIfo、tb_info、tb_infoType、tb_customer和tb_personnel。

管理员登录后,选择“发送短信”命令,进入到发送短信页面。在该页面中展开“名片夹”中的客户列表或员工列表,将显示相应的客户名称或员工姓名,单击指定的客户名称或员工姓名,系统会自动将该客户或员工的手机号码添加到右侧的“接收方手机号码”文本框中。如果用户想从信息库中选择常用短语直接添加到“短信内容”文本框中,可以先在“添加常用短语”下拉列表框中选择相应的类别,然后单击“确定”按钮,在打开的网页对话框中单击要添加的信息,即可将该信息添加到“短信内容”文本框中。短信内容填写完毕,单击“发送”按钮即可发送。发送短信页面的运行效果如图4-9 所示。

4-9 企业快信的短信发送界面

4.5.3  发送短信模块技术分析

在实现发送短信模块时,需要编写发送短信模块对应的ActionForm类和Action实现类。下面将详细介绍如何编写发送短信模块的ActionForm类和创建发送短信的Action实现类。

  1. 编写收发短信的ActionForm类

在发送短信模块中,涉及到tb_shortLetter(短信表)、tb_customer(客户信息表)、tb_personnel(员工信息表)、tb_shortInfo(常用短语表)、tb_infoType(信息类型表)和tb_Parameter(系统参数表)6个数据表,与这6个数据表相对应的ActionForm类分别为ShortLetterForm、CustomerForm、PerrsonnelForm、shortInfoForm、InfoTypyForm、ParameterForm,这些类都是由属性及对应的getXXX()和setXX()方法组成,不再详细介绍。

(2) 创建发送短信的Action类

收发短信模块的Action实现类SendLetter维承了Action类.在该类中.首先需要在该类的构造方法中分别实例化收发短信模块的SendLetterDAO类、员工管理摸块的PersonnelDAO类、客户管理模块的CustomerDAO类和信息类别管理模块的InfoTypeDAO类。Action实现类的主要方法是execute(),该方法会被自动执行其本身没有具体的事务,是根据HttpServletRequest的getParameter()方法获取的Action参数值执行相应方法的。发送短信模块Action实现类的关健代码如下:

public class SendLetter extends Action{

    private SendLetterDAO sendLetterDAO = null;

    private PersonnelDAO personnelDAO=null;

    private CustomerDAO customerDAO=null;

    private InfoTypeDAO infoTypeDAO=null;

    private ChStr chStr=new ChStr();

    public SendLetter() {

        this.sendLetterDAO = new SendLetterDAO();

        this.personnelDAO=new PersonnelDAO();

        this.customerDAO=new CustomerDAO();

        this.infoTypeDAO=new InfoTypeDAO();

    }

public ActionForward execute(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response){

        String action = request.getParameter("action");

        System.out.println("获取的查询字符串:" + action);

        if (action == null || "".equals(action)) {

         request.setAttribute("error","您的操作有误!");

            return mapping.findForward("error");

        }else if ("addLetter".equals(action)) {

            return addLetter(mapping, form, request,response);

        }else if("sendLetter".equals(action)){

            return sendLetter(mapping, form, request,response);

        }else if("historyQuery".equals(action)){

         return queryHistory(mapping, form, request,response);

        }

request.setAttribute("error", "操作失败!");

return mapping.findForward("error");

}

    //编写短信页面应用的查询方法,用于查询收信人列表信息类别

    private ActionForward addLetter(ActionMapping mapping, ActionForm form,

              HttpServletRequest request,HttpServletResponse response) {

        request.setAttribute("personnelQuery",personnelDAO.query(0));

        request.setAttribute("customerQuery",customerDAO.query(0));

        request.setAttribute("shortInfo",infoTypeDAO.query(0));

        return mapping.findForward("addLetter");

    }

    //群发短信

    private ActionForward sendLetter(ActionMapping mapping, ActionForm form,

               HttpServletRequest request,HttpServletResponse response){

     SendLetterForm sendLetterForm=(SendLetterForm) form;

     sendLetterForm.setContent(chStr.toChinese(sendLetterForm.getContent()));

     sendLetterForm.setFromMan(chStr.toChinese(sendLetterForm.getFromMan()));

        String ret=sendLetterDAO.sendLetter(sendLetterForm);

        if(ret.equals("ok")){

         return mapping.findForward("sendLetter");

        }else{

            request.setAttribute("error",ret);

            return mapping.findForward("error");

        }

    }

    //查看历史记录

    private ActionForward queryHistory(ActionMapping mapping, ActionForm form,

              HttpServletRequest request, HttpServletResponse response) {

        request.setAttribute("history",sendLetterDAO.query());

        return mapping.findForward("queryHistory");

    }

}

(3) 编写发送短信的SendLetterDAO类的方法

发送短信使用的sendLetterDAO类的方法是sendLetter()。在sendLettr()方法中,首先从数据表tb_parameter中查询出系统参数(即使用飞信接口发送短信所使用的端口、帐号、密码等参数),然后调用发送短信的方法mySend(),最后将发送短信的日志信息保存到数据表tbshortLetter中。sendLetter()方法的具体代码如下:

public class SendLetterDAO {

private ConnDB conn=new ConnDB();

List parameter = ParameterDAO.query();

ParameterForm parameterForm = (ParameterForm) parameter.get(0);

private smssend smssendinformation = null;

// 发送短信

public String sendLetter(SendLetterForm s) {

String ret = "";

String info="";

String sendnum="";

String flag="";

try {

String sql_p="SELECT  * FROM tb_parameter";

ResultSet rs=conn.executeQuery(sql_p);

if(rs.next()){

String phone=parameterForm.getDevice();

     String pwd=parameterForm.getBaud();

info=s.getContent();

sendnum=s.getToMan();

flag=mySend(phone,pwd,sendnum,info);//发送短信

if(flag.equals("ok")){

            String sql = "INSERT INTO tb_shortLetter values(null,'" +s.getToMan() +"','"+s.getContent()+"','"+s.getFromMan()+"',now())";

            int r= conn.executeUpdate(sql);

            System.out.println("添加短信发送历史记录的SQL:" + sql);

            if(r==0){

             ret="添加短信发送历史记录失败!";

            }else{

             ret="ok";

            }

}else{

ret=flag;

}

}else{

ret="发送短信失败!";

}

} catch (Exception e) {

System.out.println("发送短信产生的错误:" + e.getMessage());

ret = "发送短信失败!";

}finally{

conn.close();

}

return ret;

}

public static String mySend(String phone,String pwd,String to,String msg) throws HttpException, IOException{

String ret="";

        HttpClient client = new HttpClient();  

        PostMethod post = new PostMethod("http://quanapi.sinaapp.com/fetion.php");

post.addRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=utf-8");//在头文件中设置转码   

        NameValuePair[] data ={   

               new NameValuePair("u", phone),  

               new NameValuePair("p", pwd),  

               new NameValuePair("to",to),  

               new NameValuePair("m",msg),  

               };  

        post.setRequestBody(data);  

        client.executeMethod(post);  

        Header[] headers = post.getResponseHeaders();  

        int statusCode = post.getStatusCode();  

        System.out.println("statusCode:"+statusCode);  

        for(Header h : headers){  

            System.out.println(h.toString());  

        }  

        post.releaseConnection();

        ret = "ok";

        return ret;}

    //中间省略查询日志的代码

}

(4) struts-config.xml文件配置

在struts-config.xml文件中配置发送短信所设计的<forward>元素。代码如下:

<forward name=”sendLetter” path=”/sendLetter_ok.jsp”/>

4.5.4  单元测试

在开发完收发短信模块后,为了保证程序正常运行,要对模块进行单元测试.单元测试在程序开发中非常重要,只有通过单元测试才能发现模块中的不足之处,才能及时地纠正程序中出现的错误。进入到发送短信页面,在“接收方手机号码”文本框中

输入相应的手机号码(多个手机号码间用逗号分隔),在“短信内容”文本框中输入短信内容后,单击“发送”按钮,正常情况下,会弹出“短信发送成功”的提示对话框,如果发送失败,则会弹出“短信发送失败”的提示对话框。

4.6  发送邮件模块设计

4.6.1  发送邮件模块功能概述

发送邮件模块也是企业快信系统的核心模块之一,操作员可以通过该模块对企业内部的所有或者部分员工,以E-mail 电子邮件的形式发送企业通知、工资条等。另外,由于E-mail 有信息容量大、包含附件的两大优点,使它支持更多的信息内容,可以携带更丰富的资料,比较适合发送技术信息、会议主题、工作内容等信息,并且这个信息是群体发送的。该模块的运行效果如图4-10 所示。

图4-10 企业快信的邮件发送界面

4.6.2  发送邮件模块技术分析

在实现邮件发送模块时,需要编写邮件发送模块对应的ActionForm类和Action实现类。下面将详细介绍如何编写邮件发送模块的ActionForm类和创建邮件发送的Action实现类。

(1) 编写邮件群发的ActionForm类

虽然在邮件发送模块中,只涉及到tb_customer(客户信息表)和tb_personnel(员工信息表)两个数据表,但是邮件群发并不是只涉及到与这两个数据表相对应的ActionForm类--CustomerForm和PcrsonnelForm,本模块中还涉及到用于获取发送邮件所需的表单信息的ActionForm类―sendMailForm. 

(2) 创建邮件发送的Action实现类

邮件发送模块的Action实现类SendMail继承了Action类。在该类中,首先需要在该类的构造方法中分别实例化邮件发送模块的SendMailDAO类、员工管理模块的PersonnelDAO类和客户管理模块的customerDAO类.Action实现类的主要方法是execute(),该方法会被自动执行.这个方法本身没有具体的事务,它是根据HttpServletRequest的getParameter()方法获取的action参数值执行相应方法的。邮件发送模块Action实现类的关键代码如下:

public class SendMail extends Action{

    private SendMailDAO sendMailDAO = null;

    private PersonnelDAO personnelDAO=null;

    private CustomerDAO customerDAO=null;

    private ChStr chStr=new ChStr();

    public SendMail() {

        this.sendMailDAO = new SendMailDAO();

        this.personnelDAO=new PersonnelDAO();

        this.customerDAO=new CustomerDAO();

    }

public ActionForward execute(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response){

        String action = request.getParameter("action");

        System.out.println("获取的查询字符串:" + action);

        if (action == null || "".equals(action)) {

     request.setAttribute("error","您的操作有误!"); //将错误信息保存到error中

            return mapping.findForward("error"); //转到显示错误信息的页面

        }else if ("addMail".equals(action)) {

            return addMail(mapping, form, request,response);

        }else if("sendMail".equals(action)){

            return sendMail(mapping, form, request,response);

        }

request.setAttribute("error", "操作失败!");

return mapping.findForward("error");

}

}

4.6.3  发送邮件模块实现过程

(1) 发送邮件的Action实现类

在邮件群发页面中填写相应的邮件信息后,单击“发送”按钮,网页会访问一个URL,即sendMail.do?action=sendMail。从该URL地址中可以知道发送邮件时涉及到的action的参数值为sendMail,也就是当action=sendMail时,会调用群发邮件的方法sendMail()。具体代码如下:

if("sendMail".equals(action)){

      return sendMail(mapping, form, request,response);

}

在发送邮件的方法sendMail()中,首先需要将接收到的表单信息强制转换成ActionForm类型,并用获得指定属性的getXXX()方法获取主题、附件、内容属性并进行转码后,再使用setXXX()方法重新设置该属性,然后调用SendMailDAO类中的sendMail()方法发送邮件,并将返回值保存到变量ret中。如果返回值为ok,则表示邮件发送成功,将页面重定向到邮件发送成功页面:否则,将错误提示信息保存到HttpservletRequest对象的errror参数中,并且将页面重定向到错误提示信息页面.群发邮件的方法sendMail()的具体代码如下:

private ActionForward sendMail(ActionMapping mapping, ActionForm form,

HttpServletRequest request,HttpServletResponse response){

     SendMailForm sendMailForm=(SendMailForm) form;

     sendMailForm.setTitle(chStr.toChinese(sendMailForm.getTitle()));

     sendMailForm.setAdjunct(chStr.toChinese(sendMailForm.getAdjunct()));

     sendMailForm.setContent(chStr.toChinese(sendMailForm.getContent()));

     int ret=sendMailDAO.sendMail(sendMailForm);

     if(ret==0){

         request.setAttribute("error","邮件发送失败!");

         return mapping.findForward("error");

     }else{

         return mapping.findForward("sendMail");

     }

}

(2) 编写发送邮件的SendMailDAO类的方法

发送邮件使用的SendMailDA0类的方法是sendMail()。具体代码如下:

public int sendMail(SendMailForm s) {

int ret = 0;

String from = s.getAddresser();

String to = s.getAddressee();

String subject = s.getTitle();

String content = s.getContent();

String password = s.getPwd();

String path = s.getAdjunct();

try {

String mailserver ="smtp."+from.substring(from.indexOf('@')+1,from.length()); //在Internet上发送邮件时的代码

Properties prop = new Properties();

prop.put("mail.smtp.host", mailserver);

prop.put("mail.smtp.auth", "true");

Session sess = Session.getDefaultInstance(prop);

sess.setDebug(true);

MimeMessage message = new MimeMessage(sess);

message.setFrom(new InternetAddress(from)); // 给消息对象设置发件人

//设置收件人

String toArr[]=to.split(",");

InternetAddress[] to_mail=new InternetAddress[toArr.length];

for(int i=0;i<toArr.length;i++){

to_mail[i]=new InternetAddress(toArr[i]);

}

   message.setRecipients(Message.RecipientType.BCC,to_mail);

//设置主题

message.setSubject(subject);

Multipart mul = new MimeMultipart(); // 新建一个MimeMultipart对象来存放多个BodyPart对象

BodyPart mdp = new MimeBodyPart(); // 新建一个存放内容的BodyPart对象

mdp.setContent(content, "text/html;charset=gb2312");

mul.addBodyPart(mdp); // 将含有信件内容的BodyPart加入到MimeMulitipart对象中

if(!path.equals("") && path!=null){ //当存在附件时

// 设置信件的附件(用本机上的文件作为附件)

mdp = new MimeBodyPart(); // 新建一个存放附件的BodyPart

String adjunctname = new String(path.getBytes("GBK"), "ISO-8859-1"); // 此处需要转码,否则附件中包括中文时,将产生乱码

path = (System.getProperty("java.io.tmpdir") + "/" + path).replace("\\", "/");

System.out.println("路径:" + path);

FileDataSource fds = new FileDataSource(path);

DataHandler handler = new DataHandler(fds);

mdp.setFileName(adjunctname);

mdp.setDataHandler(handler);

mul.addBodyPart(mdp);

}

message.setContent(mul); // 把mul作为消息对象的内容

message.saveChanges();

Transport transport = sess.getTransport("smtp");

// 以smtp方式登录邮箱,第1个参数是发送邮件用的邮件服务器SMTP地址,第2个参数为用户名,第3个参数为密码

transport.connect(mailserver, from, password);

transport.sendMessage(message, message.getAllRecipients());

transport.close();

ret = 1;

} catch (Exception e) {

e.printStackTrace();

System.out.println("发送邮件产生的错误:" + e.getMessage());

ret = 0; }

return ret;

}

4.6.4  单元测试

在开发完邮件群发模块后,为了保证程序正常运行,一定要对模块进行单元测试,下面是原始的实现邮件发送的代码:

if(!path.equals("") && path!=null){ //当存在附件时

// 设置信件的附件(用本机上的文件作为附件)

mdp = new MimeBodyPart(); // 新建一个存放附件的BodyPart

String adjunctname=path;

path = (System.getProperty("java.io.tmpdir") + "/" + path).replace("\\", "/");

System.out.println("路径:" + path);

FileDataSource fds = new FileDataSource(path);

DataHandler handler = new DataHandler(fds);

mdp.setFileName(adjunctname);

mdp.setDataHandler(handler);

mul.addBodyPart(mdp);

通过上面的代码实现的邮件群发会存在以下问题:当发送带有中文名称的邮件后.使用Outlook软件接收邮件时,附件的名称将产生乱码。这是因为在邮件群发的Action类中,己经将接收到的附件名称转换为GBK编码格式,而在OutLook接收附件时,采用的编码格式为ISO-8859-1,所以此处还需要将其转换为巧IOS-8859-1编码格式。那为什么还要在Action类中进行转码呢?这是因为如果不进行转换,在类中通过文件名获取文件路径时,将不能正常获取。修改后的完成邮件群发的代码如下:

if(!path.equals("") && path!=null){ //当存在附件时

// 设置信件的附件(用本机上的文件作为附件)

mdp = new MimeBodyPart(); // 新建一个存放附件的BodyPart

String adjunctname = new String(path.getBytes("GBK"), "ISO-8859-1"); // 此处需要转码,否则附件中包括中文时,将产生乱码

path = (System.getProperty("java.io.tmpdir") + "/" + path).replace("\\", "/");

System.out.println("路径:" + path);

FileDataSource fds = new FileDataSource(path);

DataHandler handler = new DataHandler(fds);

mdp.setFileName(adjunctname);

mdp.setDataHandler(handler);

mul.addBodyPart(mdp);


5  技术分析

5.1  开发技巧与难点分析

5.1.1  添加收信人

为了方便用户,系统中需要提供通过单击客户列表(或员工列表)中的客户全称(或员工姓名),即可将该客户(或员工)的联系手机号码添加到“接收方手机号码”文本框中的功能。实现该功能时.需要编写自定义的JavaScript函教add(),在该函数中需要对手机号码进行验证并实现累加手机号码到“接收方手机号码”文本框中的功能。Add()函数的具体代码如下:

function add(mobileTel){

if(checkTel(mobileTel)){

s=form1.toMan.value;

if(s.length>=11){

arrS=s.split(",");

flag=false; //标记是否已经添加

for(i=0;i<arrS.length;i++){

if(arrS[i]==mobileTel){ //判断该手机号码是否已经添加

flag=true;

break;

}

}

if(!flag){

form1.toMan.value=s+","+mobileTel;

}

}else{form1.toMan.value=mobileTel;}

}

}

5.1.2  插入短信

为了方便用户,系统中需要提供将信息库中保存的常用短语添加到“短信内容”文本框中的功能。实现该功能的具体步骤如下:

(1)在发送短信页面的“添加常用短语”下拉列表框的右侧添加一个“确定”按钮,在该按钮的onClick事件中调用自定义的Javascript函数deal()。关键代码如下:

function deal(infoType,text){

var someValue;

var str="window.showModalDialog('shortInfo.do?action=selectShortInfo&id="+infoType+"','','dialogWidth=520px;\

dialogHeight=430px;status=no;help=no;scrollbars=no')";

someValue=eval(str);

if(someValue!=undefined){text.value=text.value+someValue;

}

(2)创建选择指定类别的常用短语的页面selectShortInfo.jsp,并且在该页面中添加用于将选择的常用短语返回到打开该窗口的交量,并且关闭当前窗口的自定义JavaScript函数selectInfo().selectInfo()函数的具体代码如下:

<script language="javascript">

function selectInfo(info){

window.returnValue=info;

window.close();}

</script>

(3)在selectShortInfo.jsp中显示常用短语的代码上添加一个空的超链接,并且在其onClick事件中调用selectInfo()函数。具体代码如下:

<a href="#" onClick="selectInfo('<%=s.getContent()%>')"><%=s.getContent()%></a>

5.2  使用Java Mail 组件

Java Mail Sun 公司发布用来处理E-mail API,是一种可选的、用于读取、编写和发送电子消息的包(标准扩展)。使用Java Mail 可以创建MUAMail User Agent,邮件用户代理的简称)类型的程序,它类似于EudoraPine Microsoft Outlook 等邮件程序。其主要目的不是像发送邮件或提供MTAMail Transfer Agent,邮件传输代理)类型程序那样用于传输、发送和转发消息,而是可以与MUA 类型的程序交互,以阅读和撰写电子邮件。MUA 依靠MTA 处理实际的发送任务。Java Mail API 中提供很多用于处理E-mail 的类,其中比较常用的有Session(会话)类、Message(消息)类、Address(地址)类、 Authenticator(认证方式)类、Transport(传输)类、Store(存储)类和Folder(文件夹)类7 个类。这7 个类都可以在Java Mail API 的核心包mail.jar 中找到,下面进行详细介绍。

5.2.1  Session 类

Java Mail API 中提供了Session 类,用于定义保存诸如SMTP 主机和认证的信息的基本邮件会话。通过Session 会话可以阻止恶意代码窃取其他用户在会话中的信息(包括用户名和密码等认证信息),从而让其他工作顺利执行。

每个基于Java Mail 的程序都需要创建一个Session 或多个Session 对象。由于Session 对象利用java.util.Properties 对象获取诸如邮件服务器、用户名、密码等信息,以及其他可在整个应用程序中共享的信息, 所以在创建Session 对象前, 需要先创建java.util.Properties 对象的实例。创建java.util.Properties 对象的实例的代码如下:

Properties props=new Properties();

创建Session 对象可以通过以下两种方法,不过通常情况下会使用第二种方法创建共享会话。

1)使用静态方法创建Session 的语句如下:

Session session = Session.getInstance(props, authenticator);

2)创建默认的共享Session 的语句如下:

Session defaultSession = Session.getDefaultInstance(props, authenticator);

如果在进行邮件发送时,不需要指定认证方式,可以使用空值(null)作为参数authenticator 的值。例如创建一个不需要指定认证方式的Session 对象的代码如下:

Session mailSession=Session.getDefaultInstance(props,null);

5.2.2  Address 类

Address 类用于设置电子邮件的响应地址。Address 类是一个抽象类,要使用该抽象类可以使用其子类InternetAddress,该类保存在javax.mail.internet 包中,可以按照指定的内容设置电子邮件的地址。如果想对InternetAddress 类进行操作,首先要实例化该类的一个对象。在实例化该类的对象时,有以下两种方法。

创建带有电子邮件地址并显示其他标识信息的地址,可以将电子邮件地址和附加信息同时传递给InternetAddress 类的构造方法。代码如下:

InternetAddress address = new InternetAddress("wgh717@sohu.com","WangGuoHui");

5.2.3  Authenticator 类

Authenticator 类通过用户名和密码来访问受保护的资源。Authenticator 类是一个抽象类,要使用该抽象类首先需要创建一个Authenticator 的子类,并重载getPasswordAuthentication()方法。具体代码如下:

class WghAuthenticator extends Authenticator {

public PasswordAuthentication getPasswordAuthentication() {

String username = "wgh"; //邮箱登录账号

String pwd = "111"; //登录密码

return new PasswordAuthentication(username, pwd);

}

}

然后再通过以下代码实例化新创建的Authenticator 的子类,并将其与Session 对象绑定。

Authenticator auth = new WghAuthenticator ();

Session session = Session.getDefaultInstance(props, auth);

5.2.4  Transport 类

Transport 类用于使用指定的协议(通常是SMTP)发送电子邮件。Transport 类提供了以下两种发送电子邮件的方法:

1)只调用其静态方法send(),按照默认协议发送电子邮件。代码如下:

Transport.send(message);

2)首先从指定协议的会话中获取一个特定的实例,然后传递用户名和密码,再发送信息,最后关闭连接。代码如下:

Transport transport =sess.getTransport("smtp");

transport.connect(servername,from,password);

transport.sendMessage(message,message.getAllRecipients());

transport.close();

在发送多个消息时,建议采用第二种方法,因为它将保持消息间活动服务器的连接,而使用第一种方法时,系统将为每一个方法的调用建立一条独立的连接。


结 论

通过一个典型实用的企业快信应用系统,系统地介绍了如何利用JSP应用程序,实现群发手机短信和群发电子邮件的方法。在实现该企业快信系统时,还添加了几个方便用户使用的功能,例如利用名片夹管理名片信息,以及利用信息库管理信息模板,这样用户就不用反复地填写收信人列表以及编写重复的信息了。

该系统从问题定义到可行性研究、需求分析、总体设计、详细设计直到最后的系统测试,基本上实现了设计要求的各项功能。实现了名片夹管理、信息库管理、短信发送、邮件群发、系统设置等功能。每个模块都提供了相关的数据库操作,如增、删、查、改。在开发中,采用了 MySQL 数据库、JAVA MAIL 组件技术。短信群发,邮件群发能做到为企业提供实际的应用服务。

本系统的特点是利用飞信API的原理及方法,实现对单人或多人进行发送短信并利用 JAVA MAIL API 组件的一些类方法实现了邮件群发功能,方便了企业内部之间沟通交流更加方便快捷。但由于时间有限,系统还有很多不足之处。比如系统界面设计不够美观,我会在以后的学习和工作之余不断完善。


参考文献

[1]  刘春.企业级JavaMail在Oracle系统中部署[J]. 指挥信息系统与技术,2013,(01)

[2]  邱宏茂,许朝阳,盖磊. 基于JavaMail的Web Mail系统的实现 [J].计算机应用与软件, 2005,(06) 

[3]  王文帅,张红梅.基于JavaMail的点对点邮件批量发送系统 [D]. 第14届全国计算机、网络在现代科学技术领域的应用学术会议,2009

[4]  刘芳. 基于短信猫的短信发送平台的设计与实现 [J]. 电脑知识与技术,2013,(31)

[5]  原泉,蔡晶.针对短信猫接收短信的安全风险分析 [J]. 计算机安全, 2013,(06)

[6]  徐宇斐.企业快信系统的设计与实现 [D].吉林大学,(2013)

[7]  路高鹏.短信群发软件的设计与实现 [J].计算机与网络,2013,(05)

[8]  Ratecki, Krzysztof; Sakowicz, Bartosz.Configurable client email application working as web page [R] .MODERN PROBLEMS OF RADIO ENGINEERING, TELECOMMUNICATIONS AND COMPUTER SCIENCE, PROCEEDINGS,2006,(06)

[9]  Kuantama, Endrowednes; Mardjoko, Pono.Design and Construction of Early Flood Warning System Through SMS based on SIM300C GSMModem [R]. (ICICI-BME) ,2013,(03)

[10]  Lv, Fangxing; Xie, Xiaoyao; Zhang, Cuicui. Research and Development of E-mail Program Based on Java [J]. PROCEEDINGS OF THE 3RD INTERNATIONAL CONFERENCE ON ANTI-COUNTERFEITING, SECURITY, AND IDENTIFICATION IN COMMUNICATION,2009


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/600161.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入理解Java虚拟机(JVM)

引言&#xff1a; Java虚拟机&#xff08;JVM&#xff09;是Java平台的核心组件&#xff0c;它负责将Java字节码转换成平台特定的机器指令&#xff0c;并在相应的硬件和操作系统上执行。JVM的引入使得Java语言具有“一次编写&#xff0c;到处运行”的跨平台特性。本文将深入探…

【练习2】

1.汽水瓶 ps:注意涉及多个输入&#xff0c;我就说怎么老不对&#xff0c;无语~ #include <cmath> #include <iostream> using namespace std;int main() {int n;int num,flag,kp,temp;while (cin>>n) {flag1;num0;temp0;kpn;while (flag1) {if(kp<2){if(…

初识C++ · 类和对象(下)

目录 1 再谈构造函数 2 类中的隐式类型转换 3 Static成员 4 友元和内部类 5 匿名对象 6 编译器的一些优化 1 再谈构造函数 先看一段代码&#xff1a; class Date { public :Date(int year, int month, int day){_year year;_month month;_day day;} private:int _ye…

Redis线程模型

文章目录 &#x1f496; Redis 单线程模型⭐ 单线程监听大量的客户端连接⭐ Redis 6.0 之前为什么不用多线程&#xff1f; &#x1f496; Redis多线程⭐ Redis 后台线程⭐ Redis 网络IO多线程 对于读写命令来说&#xff0c;Redis 一直是单线程模型。不过&#xff0c;在 Redis 4…

TinyXML-2介绍

1.简介 TinyXML-2 是一个简单、小巧的 C XML 解析库&#xff0c;它是 TinyXML 的一个改进版本&#xff0c;专注于易用性和性能。TinyXML-2 用于读取、修改和创建 XML 文档。它不依赖于外部库&#xff0c;并且可以很容易地集成到项目中。 tinyXML-2 的主要特点包括&#xff1a…

华为:三层交换机与路由器连通上网实验

三层交换机是一种网络交换机&#xff0c;可以实现基于IP地址的高效数据转发和路由功能&#xff0c;通常用于大型企业、数据中心和校园网络等场景。此外&#xff0c;三层交换机还支持多种路由协议&#xff08;如OSPF、BGP等&#xff09;&#xff0c;以实现更为复杂的网络拓扑结构…

automa警惕通过点击元素打开新的标签页,因为你可能会被他蒙蔽!

大家好&#xff0c;我是大胡子&#xff0c;专注于研究RPA实战与解决方案。 我们经常用到automa里面的【点击元素】组件&#xff0c;但要警惕通过点击元素打开新的标签页&#xff0c;例如下面这个场景&#xff0c;点击公众号的图文消息&#xff0c;之后&#xff0c;要自动输入标…

python环境下labelImg图片标注工具的使用

labelimg GitHub地址 python环境下labelImg图片标注工具的使用 1. 写在开头2. 如何使用2.1安装2.2 启动2.2.1 先启动后设置标注的目录2.2.2 指定标注的目录和预设置的标签 2.3 设置自动保存和显示类别。2.4 保存文件类型2.5 [快捷键](https://github.com/HumanSignal/labelImg…

【数据结构】C/C++ 带头双向循环链表保姆级教程(图例详解!!)

目录 一、前言 二、链表的分类 &#x1f95d;单链表 &#x1f95d;双链表 &#x1f95d;循环链表 &#x1f95d;带头双向循环链表 &#x1f34d;头节点&#xff08;哨兵位&#xff09;的作用 ✨定义&#xff1a; ✨作用&#xff1a; &#x1f347;总结 三、带头双向循环链表 …

技术速递|使用 .NET 为 Microsoft AI 构建可扩展网关

作者&#xff1a;Kara Saucerman 排版&#xff1a;Alan Wang Microsoft AI 团队构建了全面的内容、服务、平台和技术&#xff0c;以便消费者在任何设备上、任何地方获取他们想要的信息&#xff0c;并为企业改善客户和员工的体验。我们的团队支持多种体验&#xff0c;包括 Bing、…

通过氧气退火增强β-Ga₂O₃二极管.中国科技大学和河北半导体研究所的研究人员在这一特定领域取得了最新重大进展

上图所示&#xff1a;&#xff08;a&#xff09;增加台面有助于提高β-Ga2O3肖特基势垒二极管的阻断电压&#xff08;b&#xff09;。 氧气退火和自对准台面终端使β-Ga2O3二极管进一步走向商业化。 虽然β-Ga2O3电力电子技术已经取得了长足的进步&#xff0c;但仍然存在挑战&…

.双链表.

题目&#xff1a; 实现一个双链表&#xff0c;双链表初始为空&#xff0c;支持 55 种操作&#xff1a; 在最左侧插入一个数&#xff1b;在最右侧插入一个数&#xff1b;将第 k&#x1d458; 个插入的数删除&#xff1b;在第 k&#x1d458; 个插入的数左侧插入一个数&#xf…

Redis(Redis配置和订阅发布)

文章目录 1.Redis配置1.网络配置1.配置文件位置 /etc/redis.conf2.bind&#xff08;注销支持远程访问&#xff09;1.默认情况bind 127.0.0.1 只能接受本机的访问2.首先编辑配置文件3.进入命令模式输入/bind定位&#xff0c;输入n查找下一个&#xff0c;shift n查找上一个&…

书生·浦语大模型实战营之XTuner多模态训练与测试

书生浦语大模型实战营之XTuner多模态训练与测试 目录 XTuner多模态训练与测试给LLM装上电子眼&#xff1a;多模态LLM原理简介文本单模态文本图像多模态 电子眼&#xff1a;LLaVA方案简介LLaVA训练阶段示意图LLaVA测试阶段示意图 项目实践环境准备XTuner安装概述Pretrain阶段Fi…

NVIDIA_SMI has failed because it couldn’t communicate with the NVIDIA driver

参考&#xff1a;https://www.zhihu.com/question/474222642/answer/3127013936 https://blog.csdn.net/ZhouDevin/article/details/128265656 nvidia-smi查看报错&#xff0c;nvcc正常 1&#xff09;查看nvidia版本 ls /usr/src | grep nvidia nvidia-550.78 2&#xff09;…

无线通信基础

这里写目录标题 通信概述什么是无线通信无线通信电磁波 通信概述 什么是无线通信 无线通信 : 是指利用电磁波信号可以在自由空间中传播的特性进行信息交换的一种通信方式 无线通信的关键技术包括调制技术、解调技术、信道编码技术、信号处理技术、天线技术等。这些技术的不断…

【mobx-入门与思考】

介绍 mobx 是 nodejs生态中的框架&#xff0c; 主要用于做状态管理&#xff0c;可以监控变量状态的变化。 nodejs中除了mobx&#xff0c;还有个redux&#xff0c;也是做状态管理的&#xff0c;都是比较成熟的框架&#xff0c;二者的选择可以参考 【nodejs状态管理: Redux VS M…

太原理工大学Python数据分析原理与应用(课外考题:8~11章)

这部分大概只考10分&#xff0c;且大部分出在选择题&#xff0c;填空最多一两个 (仅供参考) 第十章 (理解概念为主&#xff0c;无需看推导过程) 第十一章

1-1ARM开发环境搭建(GD32)

1:安装MDK最好是5.27以及以上版本&#xff0c;避免后续学习中出现相关错误 2&#xff1a;安装芯片支持包 双击安装即可&#xff0c;也可以是默认路径&#xff0c;也可以自己更改路径 3&#xff1a;安装jlink下载器驱动&#xff08;下载调试器&#xff09; 具体安装步骤如下所示…

Java 线程池 ( Thread Pool )的简单介绍

想象一下&#xff0c;你正指挥着一支超级英雄团队&#xff0c;面对蜂拥而至的敌人&#xff08;任务&#xff09;&#xff0c;不是每次都召唤新英雄&#xff08;创建线程&#xff09;&#xff0c;而是精心调配现有成员&#xff0c;高效应对。这就是Java线程池的魔力&#xff0c;…
最新文章