您的位置:首页 > 编程语言 > Java开发

java实现对服务器的自动巡检邮件通知

2017-05-07 16:34 676 查看

1、需求


之前一直是手动的巡检,然后贴图,最近服务器数量大增,有点忙不过来了。因为一直用的java,对shell脚本不是特别了解,所以这次用java写了个小项目,实现对多服务器,多任务的巡检,巡检结果有故障的会通过邮件通知。

2、功能和效果


巡检的项目主要是服务,硬盘,内存等,命令可配置,巡检结果以日期和服务器为基准输出文件,错误信息通过邮件通知管理运维人员。





 



3、代码


action:

package com.save.action;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.save.pojo.Cmd;
import com.save.until.MailUtil;
import com.save.until.PropertiesUtil;
import com.save.until.SSHCommUtil;
import com.save.until.WriteUntil;
/**
* 巡检任务
* @author zhangzhuo
*
*/
public class InspAction {
final static Logger logger = LoggerFactory.getLogger(InspAction.class);
/*    public static void main(String[] args) {
InspAction n = new InspAction();
try {
n.execute();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
logger.error("dd");
}
}*/
/**
* 执行巡检任务
* @param args
*/
public void execute() throws Exception{
List<Cmd> list = this.handlerData();
Set<String> mail = new HashSet<String>();
for (Cmd cmd : list) {
String ip = cmd.getIp();
int port = 22;
String localIp = null;
int localPort = 0;
int timeOut = 6000;
String userName = cmd.getUsername();
String password = cmd.getPassword();
String server = cmd.getServer();
String[] cmds = cmd.getCmds();
String[] result = null;
logger.info(ip+"执行巡检任务开始");
try {
result = SSHCommUtil.execShellCmdBySSH(ip, port, localIp, localPort, timeOut,
userName, password, cmds);
} catch (Exception e) {
e.printStackTrace();
logger.error(ip+"巡检,服务器连接不上");
mail.add(ip+" "+"巡检,服务器连接不上");
}
Date date = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd");
String dateString = formatter.format(date);
//1、服务存活验证 2、硬盘占用验证 3、巡检结果写入文件
if (result != null) {
for (String string : result) {
if (string.contains("ps -ef|grep java")||string.contains("ps -ef|grep mongo")||string.contains("ps -ef|grep redis")) {
if (!string.contains(server)) {
mail.add(ip+" "+server+"服务不存在");
}
}
if (string.contains("df -h")) {
String patt = "^[5]\\d{1}\\%|[5-9]\\d{1}\\%|\\d{3,}\\%$";
String group = null;
Pattern p = Pattern.compile(patt);
Matcher m = p.matcher(string);
while (m.find()) {
group = m.group();
}
if (!StringUtils.isBlank(group)) {
mail.add(ip+" "+"硬盘占用超出预警线");
}
}
WriteUntil.createFile("E:\\save", dateString, "\\"+ip+".txt", string);
}
logger.info(ip+"巡检结束");
}
}
//发送故障邮件通知
if (!mail.isEmpty()||mail.size()!=0) {
MailUtil.getInstance().sendMail(mail);
}
}
/**
* 数据处理
* @return
*/
private List<Cmd> handlerData(){
logger.info("开始加载需要巡检的服务器数据");
Cmd cmd = null;
List<Cmd> list = new ArrayList<Cmd>();
Map map = PropertiesUtil.getInstance().getAllProperty();
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
cmd =new Cmd();
cmd.setIp(entry.getKey());
Cmd cmd2 = JSON.parseObject(entry.getValue(), Cmd.class);
String[] cmds = cmd2.getShell().split(",");
cmd.setCmds(cmds);
cmd.setServer(cmd2.getServer());
cmd.setUsername(cmd2.getUsername());
cmd.setPassword(cmd2.getPassword());
list.add(cmd);
}
logger.info("数据加载完毕");
return list;
}

}


pojo:

package com.save.pojo;

public class Cmd {
private String ip;
private String username;
private String password;
private String shell;
private String[] cmds;
private String server;

public String getServer() {
return server;
}
public void setServer(String server) {
this.server = server;
}
public String getShell() {
return shell;
}
public void setShell(String shell) {
this.shell = shell;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String[] getCmds() {
return cmds;
}
public void setCmds(String[] cmds) {
this.cmds = cmds;
}
}


工具类:

package com.save.until;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SocketFactory;
/**
* SSH创建与服务器连接工具类
* @author 张卓
* 2017-4-21
*/
public class JSCHUtil {
final static Logger logger = LoggerFactory.getLogger(JSCHUtil.class);
private static JSch jsch = new JSch();
/**
* 创建Session,并打开Session连接
*
*/
public static Session createSession(String dstIp, int dstPort,
final String localIp, final int localPort, String userName,
String password, final int timeOut) throws JSchException {
//jsch.setKnownHosts("/home/foo/.ssh/known_hosts");
logger.info("开始连接:"+dstIp);
// 建立一个SSH连接
Session session = jsch.getSession(userName, dstIp, dstPort);
session.setPassword(password);

Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");//跳过主机检查
session.setConfig(sshConfig);
// 此socket工厂用于创建目标主机的socket,
// 并创建我们使用的这个socket字节流
session.setSocketFactory(new SocketFactory() {
public OutputStream getOutputStream(Socket socket)
throws IOException {
return socket.getOutputStream();
}
public InputStream getInputStream(Socket socket) throws IOException {
return socket.getInputStream();
}
public Socket createSocket(String host, int port)
throws IOException, UnknownHostException {
Socket socket = new Socket();
if (localIp != null) {
socket.bind(new InetSocketAddress(InetAddress
.getByName(localIp), localPort));
}
socket.connect(
new InetSocketAddress(InetAddress.getByName(host), port),
timeOut);
return socket;
}
});
session.connect(timeOut);
return session;
}
}


package com.save.until;
import java.util.Properties;
import java.util.Set;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.mail.util.MailSSLSocketFactory;
/**
* 邮件发送
* @author zhangzhuo
*
*/
public class MailUtil  {
final static Logger logger = LoggerFactory.getLogger(MailUtil.class);
private static MailUtil instance = new MailUtil();
private MailUtil (){}
public static MailUtil getInstance() {
return instance;
}

public void sendMail(Set<String> mail) {
String from = "XXX@qq.com";// 发件人电子邮箱
String host = "smtp.qq.com"; // 指定发送邮件的主机smtp.qq.com(QQ)|smtp.163.com(网易)

Properties properties =new Properties();

properties.setProperty("mail.smtp.host", host);// 设置邮件服务器
properties.setProperty("mail.smtp.auth", "true");// 打开认证

try {
//QQ邮箱需要下面这段代码,163邮箱不需要
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.enable", "true");
properties.put("mail.smtp.ssl.socketFactory", sf);

// 1.获取默认session对象
Session session = Session.getDefaultInstance(properties, new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("XXX@qq.com", "XXX"); // 发件人邮箱账号、授权码
}
});

// 2.创建邮件对象
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO, new InternetAddress("XXX@qq.com"));
message.setSubject("巡检故障通知");
StringBuffer sb = new StringBuffer();
for (String string : mail) {
sb.append("<div>"+string+"</div><br/><hr/>");
}
String content = sb.toString();
message.setContent(content, "text/html;charset=UTF-8");
Transport.send(message);
logger.info("故障邮件发送成功");
} catch (Exception e) {
e.printStackTrace();
}
}

}


package com.save.until;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URI;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* 读取文件工具类
* @author zhangzhuo
*
*/
public class PropertiesUtil {

private Properties props;
private URI uri;
private static PropertiesUtil ourInstance = new PropertiesUtil("/config.properties");
public static PropertiesUtil getInstance() {
return ourInstance;
}
public PropertiesUtil(String fileName){
readProperties(fileName);
}
private void readProperties(String fileName) {
try {
props = new Properties();
InputStream fis =getClass().getResourceAsStream(fileName);
InputStreamReader re=new InputStreamReader(fis,"utf-8");
props.load(re);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取某个属性
*/
public String getProperty(String key){
return props.getProperty(key);
}
/**
* 获取所有属性,返回一个map,不常用
* 可以试试props.putAll(t)
*/
public Map getAllProperty(){
Map map=new HashMap();
Enumeration enu = props.propertyNames();
while (enu.hasMoreElements()) {
String key = (String) enu.nextElement();
String value = props.getProperty(key);
map.put(key, value);
}
return map;
}
/**
* 在控制台上打印出所有属性,调试时用。
*/
public void printProperties(){
props.list(System.out);
}
/**
* 写入properties信息
*/
public void writeProperties(String key, String value) {
try {
OutputStream fos = new FileOutputStream(new File(uri));
props.setProperty(key, value);
// 将此 Properties 表中的属性列表(键和元素对)写入输出流
props.store(fos, "『comments』Update key:" + key);
} catch (Exception e) {
e.printStackTrace();
}
}

}


  

package com.save.until;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
/**
* 执行Shell工具类
* @author zhangzhuo
*
*/
public class SSHCommUtil {
final static Logger logger = LoggerFactory.getLogger(SSHCommUtil.class);
/**
* SHH连接Linux Shell,返回结果
*/
public static String[] execShellCmdBySSH(String dstIp, int dstport,
String localIp, int localPort, int timeOut, String userName,
String password, String... cmds) throws Exception {
Session session = null;
Channel channel = null;
InputStream is = null;
OutputStream os = null;
try {
session = JSCHUtil.createSession(dstIp, dstport, localIp,
localPort, userName, password, timeOut);
logger.info("开始创建channel通道!");
//创建一个channel类型的通道
channel = session.openChannel("shell");
// Enable agent-forwarding.
// ((ChannelShell)channel).setAgentForwarding(true);
// Choose the pty-type "vt102".
// ((ChannelShell)channel).setPtyType("vt102");
// Set environment variable "LANG" as "ja_JP.eucJP".
// ((ChannelShell)channel).setEnv("LANG", "ja_JP.eucJP");
channel.connect();
is = channel.getInputStream();
os = channel.getOutputStream();
String[] result = new String[cmds.length];
for (int i = 0; i < cmds.length; i++) {
result[i] = sendCommand(is, os, cmds[i]);
}
return result;
} catch (JSchException e) {
if (e.getMessage().contains("Auth fail")) {
logger.error(dstIp+"服务器验证失败");
throw new Exception("Auth error");
} else {
logger.error(dstIp+"服务器连接失败");
throw new Exception("Connect error");
}
} catch (Exception e) {
throw e;
} finally {
try {
is.close();
} catch (IOException e) {
}
try {
os.close();
} catch (IOException e) {
}
channel.disconnect();
session.disconnect();
}
}

/**
*执行Shell脚本并返回结果
*
*/
private static String sendCommand(InputStream is, OutputStream os,
String cmd) throws IOException {
logger.info("开始执行脚本!");
os.write(cmd.getBytes());
os.flush();
StringBuffer sb = new StringBuffer();
int beat = 0;
while (true) {
if (beat > 3) {
break;
}
if (is.available() > 0) {
byte[] b = new byte[is.available()];
is.read(b);
sb.append(new String(b));
beat = 0;
} else {
if (sb.length() > 0) {
beat++;
}
try {
Thread.sleep(sb.toString().trim().length() == 0 ? 1000
: 300);
} catch (InterruptedException e) {
}
}
}
return sb.toString();
}

}


package com.save.until;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

/**
* SSH工具类
*
*/
public class SSHExcuteCommandHelper {
Session session = null;
ChannelExec openChannel = null;
/**
* @param host  主机ip
* @param name 用户名
* @param pwd 密码
* @param port ssh端口
*/
public SSHExcuteCommandHelper(String host, String user, String pwd, int port) {
JSch jsch = new JSch();
try {
session = jsch.getSession(user, host, port);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setTimeout(1000);
session.setConfig(config);
session.setPassword(pwd);
} catch (JSchException e) {
e.printStackTrace();
}
}
/**
* 是否连接成功,调用如果不需要调用execCommand方法那么必须调用 disconnect方法关闭session
* @return
*/
public boolean canConnection(){
try {
session.connect();
return true;
} catch (JSchException e) {
e.printStackTrace();
return false;
}
}
/**
* 关闭连接
*/
public void disconnect(){
if (openChannel != null && !openChannel.isClosed()) {
openChannel.disconnect();
}
if (session != null && session.isConnected()) {
session.disconnect();
}
}

/**
* 执行命令
* @param command
* @return
*/
public String execCommand(String command) {
StringBuffer result = new StringBuffer();
try {
if(!session.isConnected()){
session.connect();
}
openChannel = (ChannelExec) session.openChannel("exec");
openChannel.setCommand(command);
//int exitStatus = openChannel.getExitStatus();
openChannel.connect();
InputStream in = openChannel.getInputStream();
BufferedReader reader = new BufferedReader(
new InputStreamReader(in));

String tmpStr = "";
while ((tmpStr = reader.readLine()) != null) {
result.append(new String(tmpStr.getBytes("gbk"), "UTF-8")).append("\n");
}

} catch (Exception e) {
e.printStackTrace();
result.append(e.getMessage());
} finally {
disconnect();
}
return result.toString();
}
/**
* 解析
* @param result
* @return
*/
public List<List<String>> parseResult(String result){
List<List<String>> parseResult = new ArrayList<List<String>>();
List<String> list = null;
//
for (String line : result.split("\n")) {
list = new ArrayList<String>();
String[] columns = {};
//这个是针对df命令的 [Mounted on] 其实就一个,如果用空格就会分割出两个
if(line.contains("Mounted ")){
columns = line.replace("Mounted ", "Mounted-").split(" ");
}else{
columns = line.split(" ");
}

for (String column : columns) {
if (!" ".equals(column) && !"".equals(column)) {
list.add(column);
}
}
parseResult.add(list);
}
return parseResult;
}
//测试
/*        public static void main(String args[]) {
SSHExcuteCommandHelper execute = new SSHExcuteCommandHelper("192.168.175.128", "root", "123456", 22);
System.out.println("是否连接成功"+execute.canConnection());
String s = execute.execCommand("free -m");
System.out.println("解析前");
System.out.println(s);
System.out.println("解析后");
List<List<String>> parseResult = execute.parseResult(s);
for (List<String> l : parseResult) {
System.out.println(l);
}

}*/
}


package com.save.until;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.save.action.InspAction;
/**
*
* @author zhangzhuo
*
*/
public class WriteUntil {
final static Logger logger = LoggerFactory.getLogger(WriteUntil.class);
/**
* 新建文件夹,并创建文件写入数据
*/
public static void createFile(String basePath,String filePath, String filename, String input) {
String[] dirs = filePath.split("/");
String tempPath = basePath;
for (String dir : dirs) {
if (null == dir || "".equals(dir)) continue;
tempPath += "\\" + dir;
}
//文件夹判断
File dir = new File(tempPath);//"d:\\test_dir"
if (dir.exists()) {
if (dir.isDirectory()) {
logger.info("文件夹存在");
} else {
logger.info("同名文件存在,无法创建目录");
}
} else {
logger.info("文件夹不存在,开始创建");
dir.mkdirs();
}
//文件判断
File file = new File(tempPath+filename);//"d:\\test_file.txt"
if (file.exists()) {
logger.info(filename+"已存在");
} else {
logger.info(filename+"文件不存在,开始创建");
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
//写入数据
//方法一、每次写入覆盖之前的
/* try {
FileOutputStream fos = new FileOutputStream(tempPath+filename);
fos.write(input.getBytes());
fos.close();
} catch (Exception e) {
e.printStackTrace();
}*/
try {
FileOutputStream fos = new FileOutputStream(tempPath+filename, true);
fos.write(input.getBytes());
fos.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
//测试
/*    public static void main(String[] args) {
//createFile("E:\\log", "2014/16/2/", "\\2020.txt", "hahha");
Date date = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd");
String dateString = formatter.format(date);
System.out.println(dateString);
}*/
}


applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> 
<!-- 配置作业类 -->
<bean id="InspAction"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<bean class="com.save.action.InspAction" />
</property>
<property name="targetMethod" value="execute" />
<property name="concurrent" value="false" /><!-- 作业不并发调度 -->
</bean>
<!-- 配置触发器 -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="InspAction" />
<!-- 每天7:00运行一次 -->
<property name="cronExpression" value="0 0 07 * * ?" />
</bean>
<!-- 配置调度工厂 -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger" />
</list>
</property>
</bean>

</beans>


config.properties

#测试用服务器
192.168.175.128={"username":"root","password":"123456","shell":"ps -ef|grep mongo\n,df -h\n, free -m\n, top\n","server":"mongod"}
192.168.175.129={"username":"root","password":"123456","shell":"ps -ef|grep redis\n,df -h\n, free -m\n, top\n","server":"mongod"}


log4j.properties

#指定根Logger,及日志输出级别
#大于等于该级别的日志将被输出( DEBUG < INFO < WARN < ERROR < FATAL ),设为OFF可以关闭日志
log4j.rootLogger=INFO, A1,A2
#指定log输出目的,这里设为输出日志到指定目录的文件my.log中
log4j.appender.A1=org.apache.log4j.FileAppender
log4j.appender.A1.File=E:\\save\\log\\xj.log
#指定日志信息的格式
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%r %d{yyyy-MM-dd HH:mm:ss} %c %p -%m%n

#把A2输出到控制台
log4j.appender.A2=org.apache.log4j.ConsoleAppender
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %c %p -%m%n


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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>com.save</groupId>
<artifactId>save-xj</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>save-xj Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- SSH连接 -->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.53</version>
</dependency>
<!-- json转换 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.31</version>
</dependency>
<!-- Spring的包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<!-- 定时任务 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>1.8.5</version>
</dependency>
<!-- 日志的包 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<!-- 邮件 -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.4.4</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>

</dependencies>

<build>
<plugins>
<!-- 配置Tomcat插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: