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

Struts2.5+Hibernate5.8.0实现的学生成绩管理系统

2018-02-08 11:03 537 查看

Struts2.5+Hibernate5.8.0实现的学生成绩管理系统(Javaweb项目)

该项目使用的Tomcat版本为9.0.2,JDK版本为jdk1.8.0_91,数据库为MySQL(PS:该项目前端不好看,关于struts2的配置可参照struts2的配置问题

(1)实现功能:

实现了登陆验证,必须登陆才能访问其它页面

可对数据进行分页

实现对成绩的复杂查询,如成绩等级,分数等,并且实现排序

可以将数据导出到excel表下载

实现数据库的备份和恢复

实现对输入信息的校验.

(2)运行效果以及数据库内容:

登陆界面:



查看学生信息界面:



添加学生信息界面:



数据库:



(3)关于项目的各种XML文件的配置:

a) web.xml(放在WEB-INF目录下)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:jsp="http://java.sun.com/xml/ns/javaee/jsp"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>student</display-name>
<description>MySql数据库连接池</description>
<resource-ref>
<res-ref-name>students</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

<filter>
<filter-name>login</filter-name>
<filter-class>com.mdy.filter.LoginFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>login</filter-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.action</url-pattern>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<!-- 使用标签库所需的配置 -->
<jsp-config>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
<taglib-location>/WEB-INF/c.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/fmt</taglib-uri>
<taglib-location>/WEB-INF/fmt.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/sql</taglib-uri>
<taglib-location>/WEB-INF/sql.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/x</taglib-uri>
<taglib-location>/WEB-INF/x.tld</taglib-location>
</taglib>
</jsp-config>
</web-app>


b) struts.xml(放在scr目录下)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
<!-- 指定需要Struts2处理的请求后缀 -->
<constant name="struts.action.extension" value="do,action"></constant>
<!-- 设置浏览器是否缓存静态内容,开发阶段应关闭,生产阶段打开,默认为打开 -->
<constant name="struts.serve.static.browserCache" value="false"></constant>
<!-- 当struts的配置文件修改后,系统是否自动重新加载该文件,默认为false,开发阶段应打开 -->
<constant name="struts.configuration.xml.reload" value="true"></constant>
<!-- 开发模式下使用,可以打印出更详细的错误信息 -->
<constant name="struts.devMode" value="true"></constant>
<!-- action全部用注解进行配置 -->
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<!-- 是否开启动态方法调用 -->

<package name="default" namespace="/JSP" extends="struts-default">
<global-results>
<result name="error">/JSP/error.jsp</result>
</global-results>

<global-allowed-methods>add,execute,search,jump,del,revise,login</global-allowed-methods>

<action name="login" class="com.mdy.action.Login" method="login">
<result name="success">/JSP/add_student.jsp</result>
<result name="login_error">/JSP/login.jsp</result>
</action>
<action name="add" class="com.mdy.action.AddAction" method="add">
<result name="success">/JSP/add_success.jsp</result>
<result name="error_exist">/JSP/add_error_exist.jsp</result>
<result name="input">/JSP/add_student.jsp</result>
</action>
<action name="search" class="com.mdy.action.GetData" method="search">
<result name="success">/JSP/ViewData.jsp</result>
</action>
<action name="jump" class="com.mdy.action.GetData" method="jump">
<result name="success">/JSP/ViewData.jsp</result>
</action>
<action name="del" class="com.mdy.action.ReviseData" method="del">
<result name="success">/JSP/del_success.jsp</result>
</action>
<action name="revise" class="com.mdy.action.ReviseData" method="revise">
<result name="success">/JSP/revise_success.jsp</result>
</action>
</package>
</struts>


c) hibernate-cfg-xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/student?useUnicode=true&characterEncoding=UTF-8&useSSL=false</property>
<property name="connection.username">admin</property>
<property name="connection.password">admin</property>

<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">10</property>

<!--jdbc.fetch_size是指Hibernate每次从数据库中取出并放到JDBC的Statement中的记录条数。Fetch Size设的越大,读数据库的次数越少,速度越快,
          Fetch Size越小,读数据库的次数越多,速度越慢-->
<property name="jdbc.fetch_size">100</property>

<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>

<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>

<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

<!-- Echo all executed SQL to stdout -->
<property name="show_sql">false</property>

<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">update</property>

<!-- <property name="hibernate.search.default.directory_provider">filesystem</property>
<property name="hibernate.search.default.indexBase">target/indexes</property> -->
<mapping resource="com\mdy\bean\User.hbm.xml" />
<mapping resource="com\mdy\bean\Student.hbm.xml" />

</session-factory>
</hibernate-configuration>


(4)功能实现:

1.登陆验证实现返回顶部

(a)实现方法:采用了servlet的过滤器

(b)具体实现:

a) 过滤器起作用在web.xml的配置:

<filter>

<filter-name>login</filter-name>

<filter-class>com.mdy.filter.LoginFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>login</filter-name>

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

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

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

</filter-mapping>


(PS:最好将该过滤配置写在struts2的过滤上面,不然过滤器可能会不起作用

b) 过滤器的类:

@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
HttpSession session = request.getSession();
String path = request.getServletPath();//获得要访问的页面的名字
String flag = (String) session.getAttribute("flag");//flag为识别是否已经登陆过的session
System.out.println(flag+path);
if (path == null || path.equals("/JSP/login.jsp")|| path.equals("/JSP/login.action")) {//不能过滤掉登陆界面和动作
arg2.doFilter(arg0, arg1);
} else {//登陆失败一律采用页面重定向到登陆界面
if(flag==null) {
request.setAttribute("msg", "用户未登陆!!");
RequestDispatcher rd = request.getRequestDispatcher("/JSP/login.jsp");
rd.forward(request, response);
}
else {
if (flag.equals("登陆成功")) {
arg2.doFilter(arg0, arg1);
}
else {
request.setAttribute("msg", "请登陆");
RequestDispatcher rd = request.getRequestDispatcher("/JSP/login.jsp");
rd.forward(request, response);
}
}
}
}
}


2.分页功能实现返回顶部

(a)实现方法:使用一个bean:PageBean,储存要显示的数据和当前页面的信息,将储存在session中。数据库的操作采用了Hibernate的HQL语句和标准查询API,详细实现在第三点的复合搜索加排序的实现

(b)具体实现:

a) PageBean的实现bean类:

public class Page<T>{
private int pageNum;//当前页面
private int pageTotal;//总页面
public static final int pageMax = 15;//页面的数据量
private long totalData;//数据总数
private int start;//分页栏的起始页
private int end;//分页栏的终止页
private List<T> list;//显示在当前页面的数据
//省略一部分getter和setter
//每次页码变化就对start和end进行修改
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
this.start=pageNum-2;
if(this.start<=0) {
this.start=1;
}
this.end=this.start+4;
if(this.end>pageTotal) {
this.end=pageTotal;
}
}
//设置总数据量时进行总页码计算
public void setTotalDate(long totalData) {
int t = 1;
if ((int)totalData % pageMax== 0) {
t = 0;
}
pageTotal = (int) (totalData / pageMax + t);
this.totalData = totalData;
}
}


b) 页面跳转动作的实现方法:

public String jump() throws ServletException, IOException {
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
pagebean = (Page<Student>) session.getAttribute("pagebean");//得到当前页面的pagebean
com.mdy.dao.GetData gd = new com.mdy.dao.GetData();
//判断页码是否越界
if (search.get_pageNum() > pagebean.getPageTotal()) {
search.set_pageNum(pagebean.getPageTotal());
;
}
pagebean.setList(gd.getData(Page.pageMax, search.get_pageNum(),(String)session.getAttribute("search_sql")));//得到当前页面的搜索条件
pagebean.setPageNum(search.get_pageNum());
session.setAttribute("pagebean", pagebean);
return SUCCESS;
}


c) 分页栏的JSP:

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<div align="center">
<form action="jump.action" name="page">
<ul class=page>
<li><a href="jump.action?_pageNum=1">首页</a>
<li><a
<c:if test="${_pageNum-1 gt 0}">href="jump.action?_pageNum=${_pageNum-1}"</c:if>>上一页</a>
<input style="width: 30px;" name="_pageNum" value="${pagebean.pageNum}"><!-- 跳转页面输入框 -->
<!-- 当要显示页面均大于1时 显示[...]-->
<c:if
test="${pagebean.start>1}">
<li>[...]
</c:if>
<!-- 使用JSTL的foreach显示五页 -->
<c:forEach var="i" begin="${pagebaen.start}" end="${pagebean.end}">
<c:if test="${i >= pagebean.start && i <= pagebean.end}">
<a
<c:if test="${i != pagebean.pageNum}">href="jump.action?_pageNum=${i}"</c:if>>[${i}]</a>
</c:if>
</c:forEach>
<!-- 当要显示页面均小于最大页面2时 显示[...]-->
<c:if test="${pagebean.end<pagebean.pageTotal}">
<li>[...]
</c:if>
<li><button type="submit" onclick="return CheckPage(page)">跳转</button><!-- 使用JS进行输入框内容校验 -->
<li><label>${pagebean.pageNum}/${pagebean.pageTotal}</label>
<li><a
<c:if test="${_pageNum+1 <= pagebean.pageTotal}">href="jump.action?_pageNum=${pagebean.pageNum+1}"</c:if>>下一页</a>
<li><a href="jump.action?_pageNum=${pagebean.pageTotal}">尾页</a>
</ul>
</form>
</div>


3.复合搜索加排序返回顶部

(a)实现方法:使用了Hibernate的HQL和标准查询API进行查询,将搜索框的数据按格式拼成字符串传递给数据库操作类进行操作,并将其保存在session里让分页的页面跳转使用。

(b)具体实现:

a) 数据库操作类:

private long i;//总数据量
//得到学生成绩
/*
* pageMax 页面显示的最多数据
* pageNum 页码
* str 搜索条件
* */
@SuppressWarnings({ "unchecked", "unused", "deprecation" })
public List<Student> getData(int pageMax, int pageNum, String str) throws HibernateException {
List<Student> student = null;
Configuration configuration = new Configuration().configure();
SessionFactory factory = configuration.buildSessionFactory();
Session session = factory.getCurrentSession();
Transaction transaction = session.beginTransaction();//事务开始
//判断str是否为空或需不需要搜索
if (str == null||str.equals("%% none per 0 100 asc id %%")) {
i = ((long)session.createQuery("select count(*) from Student").uniqueResult());//得到数据总数
student = session.createQuery("from Student")
.setFirstResult((pageNum - 1) * pageMax)//设置搜索得到的数据从哪里开始返回,0为第一条数据
.setMaxResults(pageMax).list();//设置返回的数据总量
}
else {
String[] string = str.split(" ");
student = session.createCriteria(Student.class).add(Restrictions.like("name", string[0]))//模糊查询姓名的语句
.add(Restrictions
.or(string[1].charAt(0) == 'n' ? Restrictions.isNotNull("level")
: Restrictions.like("level", string[1].charAt(0)))
.add(Restrictions.like("level", string[1].charAt(0))))//成绩等级的条件语句
.add(Restrictions.between(string[2], Double.parseDouble(string[3]), Double.parseDouble(string[4])))//成绩范围的查询语句
.addOrder(string[5].equals("asc") ? Order.asc(string[6]) : Order.desc(string[6]))//升降序的查询语句
.add(Restrictions.like("id", string[7]))//模糊查询学号的语句
.setFirstResult((pageNum - 1) * pageMax)
.setMaxResults(pageMax)
.list();
i = (long) session.createCriteria(Student.class).add(Restrictions.like("name", string[0]))
.add(Restrictions
.or(string[1].charAt(0) == 'n' ? Restrictions.isNotNull("level")
: Restrictions.like("level", string[1].charAt(0)))
.add(Restrictions.like("level", string[1].charAt(0))))
.add(Restrictions.between(string[2], Double.parseDouble(string[3]), Double.parseDouble(string[4])))
.addOrder(string[5].equals("asc") ? Order.asc(string[6]) : Order.desc(string[6]))
.add(Restrictions.like("id", string[7])).list().size();//得到数据总数
}
transaction.commit();//事务提交,会自动关闭由getCurrentSession()得到的session,而openSession()得到的则不会
return student;
}


4.数据导出成excel并下载返回顶部

(a)实现方法:直接使用JSP实现,使用了外部工具包poi-3.17.jar创建excel表格,并且使用了JSTL的sql标签(其实没必要),使用文件操作流时使用了response的OutputStream,需要在使用OutputStream前调用response.reset(),清空之前输出流的静态内容,否则会出错。

(b)具体实现:

a) ExcelExport.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@page import="com.mdy.bean.Student"%>
<%@page
import="java.util.SortedMap,java.io.OutputStream,java.io.FileOutputStream,java.io.File,org.apache.poi.hssf.usermodel.HSSFRow,org.apache.poi.hssf.usermodel.HSSFSheet,org.apache.poi.hssf.usermodel.HSSFWorkbook"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql"%>
<sql:setDataSource
url="jdbc:mysql://localhost:3306/student?useUnicode=true&characterEncoding=utf-8&useSSL=false"
driver="com.mysql.jdbc.Driver" user="admin" password="admin"
var="StudentDataBase" />
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<link href="main.css" rel="stylesheet" type="text/css">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>导出信息</title>
</head>
<%
HSSFWorkbook wb = new HSSFWorkbook();//创建工作簿对象
HSSFSheet sheet = wb.createSheet("学生成绩");//创建一个表
int i = 0;
HSSFRow row = sheet.createRow(i++);
row.createCell(0);
row.createCell(1);
row.createCell(2);
row.createCell(3);
row.createCell(4);
row.createCell(5);
row.createCell(6);
row.createCell(7);
row.getCell(0).setCellValue("学号");
row.getCell(1).setCellValue("姓名");
row.getCell(2).setCellValue("语文成绩");
row.getCell(3).setCellValue("数学成绩");
row.getCell(4).setCellValue("英语成绩");
row.getCell(5).setCellValue("作业成绩");
row.getCell(6).setCellValue("平均分");
row.getCell(7).setCellValue("成绩等级");
%>
<!-- 使用了JSTL的sql标签 -->
<sql:query var="res" sql="select * from student_score"
dataSource="${StudentDataBase}"></sql:query>
<!-- 使用JSTL的foreach,res为检索后得到的数据集合,res.rows为一个SortMap对象 -->
<!-- 为了在JSP里面调用re,需要将其储存在request域里面 -->
<c:forEach items="${res.rows}" var="re">
<c:set value="${re}" var="r" scope="request" />
<%
row = sheet.createRow(i++);
SortedMap sm = (SortedMap) request.getAttribute("r");
row.createCell(0);
row.createCell(1);
row.createCell(2);
row.createCell(3);
row.createCell(4);
row.createCell(5);
row.createCell(6);
row.createCell(7);
row.getCell(0).setCellValue((String) sm.get("学号"));
row.getCell(1).setCellValue((String) sm.get("姓名"));
row.getCell(2).setCellValue(String.valueOf(sm.get("语文成绩")));
row.getCell(3).setCellValue(String.valueOf(sm.get("数学成绩")));
row.getCell(4).setCellValue(String.valueOf(sm.get("英语成绩")));
row.getCell(5).setCellValue(String.valueOf(sm.get("作业成绩")));
row.getCell(6).setCellValue(String.valueOf(sm.get("平均分")));
row.getCell(7).setCellValue(String.valueOf(sm.get("成绩等级")));
%>
</c:forEach>
<%
response.reset();
OutputStream output = response.getOutputStream();//因为只能打开一个输出流,为了得到reponse的OutputStream,必须将reponse重置
//让浏览器识别其为下载文件的设置
response.setHeader("Content-disposition", "attachment; filename=poi.xls");
response.setContentType("application/msexcel");
//输出excel表格
wb.write(output);
output.close();
wb.close();
%>
<body>
</body>
</html>


5.数据备份和恢复返回顶部

(a)实现方法:使用了mysql自带的备份和恢复工具,这里笔者使用绝对路径访问,可通过配置path实现直接访问。通过得到mysql工具向控制台输出数据,将其储存在文件里面实现备份,恢复也是同理

(b)具体实现:

a) 备份的实现

Runtime rt = Runtime.getRuntime();
//调用mysql的备份工具的命令
Process child = rt.exec("g:\\mysql-5.7.20-winx64\\bin\\mysqldump -h localhost -uadmin -padmin student");
// 设置导出编码为utf-8

InputStream in = child.getInputStream();// 控制台的输出信息作为输入流

InputStreamReader xx = new InputStreamReader(in, "utf-8");
// 设置输出流编码为utf-8
String inStr;
StringBuffer sb = new StringBuffer("");
String outStr;
// 组合控制台输出信息字符串
BufferedReader br = new BufferedReader(xx);
while ((inStr = br.readLine()) != null) {
sb.append(inStr + "\r\n");
}
outStr = sb.toString();
//获得备份地址的绝对路径
FileOutputStream fout = new FileOutputStream(session.getServletContext().getRealPath("/SQL")+"/student.sql");
OutputStreamWriter writer = new OutputStreamWriter(fout, "utf-8");
writer.write(outStr);
writer.flush();
in.close();
xx.close();
br.close();
writer.close();
fout.close();


a) 恢复的实现:同理,只是换成向控制台输入信息

Process process = runtime.exec(

"g:\\mysql-5.7.20-winx64\\bin\\mysql -hlocalhost -uadmin -padmin --default-character-set=utf8 student");


6.输入校验的实现返回顶部

(a)实现方法:使用了JS实现以及struts2的校验器

(b)具体实现:

a) JS的代码:

function validate_required_name(field) {
var re_name = /^[\u4e00-\u9fa5]+$/
with (field) {
if (value == null || value == "") {
document.getElementById("_name").innerHTML = "名字不能为空"
return false
} else {
if (re_name.test(value)) {
return true
} else {
document.getElementById("_name").innerHTML = "名字必须为中文"
return false
}
}
}
}
function validate_required_score(field) {
var num = /^[0-9]+.?[0-9]*$/
with (field) {
if(value==null||value==""){
return false
}
else{
if(num.test(value)&&0<=value&&value<=100){
return true
}
else{
return false
}
}
}
}

function validate_form(thisform) {
with (thisform) {
if (validate_required_name(name) == false) {
name.focus()
return false
}
if (validate_required_score(chinese) == false) {
chinese.focus()
document.getElementById("_chinese").innerHTML = "成绩必须在0到100之间"
return false
}
if (validate_required_score(math) == false) {
math.focus()
document.getElementById("_math").innerHTML = "成绩必须在0到100之间"
return false
}
if (validate_required_score(english) == false) {
english.focus()
document.getElementById("_english").innerHTML = "成绩必须在0到100之间"
return false
}
if (validate_required_score(homework) == false) {
homework.focus()
document.getElementById("_homework").innerHTML = "成绩必须在0到100之间"
return false
}

}
}


b) struts2的校验器:(使用正则表达式时param的name值为regexExpression时才会起作用)

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

<!DOCTYPE validators PUBLIC

"-//OpenSymphony Group//XWork Validator 1.0//EN"

"http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">

<validators>
<field name="student.name">
<field-validator type="requiredstring">
<message>姓名必须输入</message>
</field-validator>
<field-validator type="regex" >
<param name="regexExpression"><![CDATA[(^[\u4e00-\u9fa5]{1,6}$)]]></param>
<message>姓名必需是长度不超过6,且必须是汉字</message>
</field-validator>
</field>

<field name="student.chinese">
<field-validator type="double">
<param name="min">0</param>
<param name="max">100</param>
<message>成绩必须在0至100之间</message>
</field-validator>
</field>

<field name="student.math">
<field-validator type="double">
<param name="min">0</param>
<param name="max">100</param>
<message>成绩必须在0至100之间</message>
</field-validator>
</field>

<field name="student.english">
<field-validator type="double">
<param name="min">0</param>
<param name="max">100</param>
<message>成绩必须在0至100之间</message>
</field-validator>
</field>

<field name="student.homework">
<field-validator type="double">
<param name="min">0</param>
<param name="max">100</param>
<message>成绩必须在0至100之间</message>
</field-validator>
</field>

<field name="student.id">
<field-validator type="requiredstring">
<message>学号必须输入</message>
</field-validator>
<field-validator type="regex">
<param name="regexExpression"><![CDATA[(\d{6})]]></param>
<message>学号必须是6位的数字</message>
</field-validator>
</field>

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