首页 > 编程 > Java > 正文

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

2019-11-26 12:23:40
字体:
来源:转载
供稿:网友

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.PatternLayoutlog4j.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>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表