Struts2、Spring、Hibernate 高效开发的最佳实践

java开发框架(Spring+Hibernate+Struts) 经过数年的“框架大战”,Java界的各种框架找到了自己应有的位置。Spring+Hibernate+Struts已成为Java开发的主流体系。在这个体系中,Spring+Hibernate的地位应该说短期内是难以撼动了。除了新兴的Jboss Seam作为挑战者之外,几乎难有劲敌 立即下载

SSH(Struts2+Spring+Hibernate)是最为 Java 业界熟知的 Java EE Web 组件层的开发技术。很多人提起 Java EE,甚至都会将其误认为就是 SSH。无论是书籍还是电子教程,大部分都已经千篇一律,讲解各种标签、配置的用法。许多人包括笔者在内,第一次使用 SSH 的时候,按照教程的介绍进行开发。繁琐的配置,重复的修改配置,不断定义的参数转换器,真的让笔者苦不堪言。本文对 SSH 的开发模式尝试了重新定义,按照规约优于配置的原则,利用 Java 反射、注解等技术,设计了新的一套 SSH 开发框架,应用该框架,可以大大提高开发效率,笔者多次将该开发框架应用在各种小型 SSH Web 应用系统之中,屡试不爽。

阅读文章之前,读者需要对 SSH 的结合开发有一些了解,最好是有实践的经验,特别是对 Struts2 需要较为了解,掌握 Struts2 自定义拦截器、自定义验证器等的开发。另外,读者还需要掌握一些前提技术,包括 Java 反射、Java 注解、理解事务隔离级别等。

文章首先进行框架的总体介绍,然后分点介绍各个部分的详细设计。另外,文章还将列举该框架中采用的技术特点及其相应目的,希望读者可以从中获益。


框架总体介绍

文章之所以说框架是通用的,因为它的思想适应任何的业务需求。按照文章介绍,按照介绍的框架搭建完代码架构后,可以屏蔽许多技术细节,让开发人员专注于业务逻辑的实现,这些繁琐的技术细节包括技术配置、权限控制、页面跳转、错误处理等等。框架大致的风格如图 1 所示,总体来说,该框架遵守了“规约优于配置”的原则。


图 1. 框架大致风格( 查看大图 )
图 1. 框架大致风格 

上图中,系统只有一个 action 配置。每个业务操作,不再对应一个 ActionSupport 子类,而是对应一个 ActionSupport 子类的类方法,利用 Struts2 的动态方法特性,使得业务方法摆脱了繁琐的配置,方便的增加和删除。全面的 result 配置,解决了各种页面跳转的问题。Action 方法的起名,遵守了权限与业务模型规约,让模型选择与权限控制交给框架来实现,同时访问的操作名就是【方法名】 .action。下面,将一一对框架的各部分进行讲解。


Struts2 的不动配置

该框架中,我们建议只定义少量的类继承于 ActionSupport,这样可以使得 struts.xml 的配置尽量减少,甚至只进行少量配置,而不用随着业务的增加而修改配置。清单 1 是笔者为一个教师考勤系统定义的 Action 配置。


清单 1. Struts2 的配置清单
				 
 <action name="*" method="{1}" class="Main"> 
     <interceptor-ref name="fileUpload"> 
         <param name="maximumSize">4073741824</param> 
     </interceptor-ref> 
     <interceptor-ref name="myInterceptorStack"></interceptor-ref> 
     <result name="input">/noDir/error.jsp</result> 
     <result type="json" name="success"></result> 
     <result name="errorJson" type="json"></result> 
     <result type="json" name="error"></result> 
     <result type="stream" name="stream"> 
         <param name="contentType">${contentType}</param> 
         <param name="contentDisposition">fileName="${inputFileName}"</param> 
         <param name="inputName">inputStream</param>  
     </result> 
     <result name="dynamic">/${url}</result> 
     <result name="otherAction" type="redirectAction">/${url}</result> 
     <result name="red" type="redirect">/${url}</result> 
 </action> 

清单 1 定义了很多规则。首先,该配置使用了动态方法调用技术,这可以使得许多的 Action 方法可以声明到一个类里,不用重复定义 Action 类,同时对业务的增加和删除可以简约到对 Action 类里方法增加和删除,增加的 Action 方法不需进行其他配置,如果业务被删除,则只需要将方法注释或者删除,非常方便。第二,配置的 package 继承于 json-default,也就是说这个包里的 action 是支持 Ajax 调用的,默认的,如果返回 ERROR、SUCCESS,则会将 Action 序列化为 JSON 返回到客户端。我们定义了各种的跳转类型,包括重定向到页面(具体的页面由 Action 里的 url 指定)、重定向到 Action、重定向到错误页面、流类型的返回等等,这为我们动态的选择返回结果数据提供了方便。那么使用上述的配置,对我们开发有什么好处呢?假设有一个新的业务,我们只需要在 Action 添加新的方法,如清单 2 所示。


清单 2. 添加新业务方法
				 
public String business() throws Exception
	{
		…business process…

		if (has error)
		{
			addFieldError(“error message”) return INPUT;
		} else {
			//url是action中定义的一个String变量,指定跳转地址
			url = “business.jsp”; return “dynamic”;
		} 
	}


调用这个新的业务方法,只需要调用这个链接:http://{host}:{port}/{webapp}/business.action。正如我们看到的,定义了新的业务逻辑方法,我们没有修改或添加任何配置,因为我们的配置是完整的,考虑到了各种跳转、错误情况,同时动态方法调用特性,让我们可以动态的指定业务方法。如果我们对清单 2 中的跳转代码进行抽取,清单 2 会更加简单。如清单 3 所示。


清单 3. 抽取基础方法后的业务方法
				 
public String business() throws Exception
{
		…business process…

		if (has error)
		{
			return redirectToErrorPage("error message")
		} else {
			return redirectToPage("business.jsp");
		}
}


上面的清单中,我们抽取了 redirectToErrorPage 和 redirectToPage 方法,这样就可以使得其他的业务方法可以重用这些跳转方法,整个业务过程变得清晰易懂。类似的我们还可以抽取出 redirectToAction(跳转到另一个业务方法)、redirectStream(流类型的跳转)、redirectToAnotherPage(用于重定向的跳转)、redirectToJson(Ajax 的跳转)等等。这样这些公共方法就可以让其他的开发人员一起使用。程序员可以从跳转、错误提示、重复配置 Action 的痛苦中解救出来,专注于编写业务逻辑。


ModelDriven 的规约

有了上面的配置,我们还不能做到完全脱离配置。比如,我们定义了一个 Action 类继承于 ActionSupport,我们知道使用 ModelDriven 可以将用户上传的数据封装到一个业务 Bean 里,而不用直接在 Action 里声明变量,这很重要。我相信有很多读者遇到过这个问题。当业务 Bean 不同时,也就是需要用户上传的数据不同时,我们就要随之添加新的 Action,这直接导致修改 struts.xml 的配置,然后还要修改 applicationContext.xml 的事务配置、Bean 的配置,哪天我们不要这个业务了,又要重复的修改删除配置,笔者开始时为此事近乎抓狂,为什么我们不能只定义一个 Action,而 ModelDriven 的模型动态改变呢?

仔细考虑 Struts2 的机制,Struts2 将客户端的参数装配到 ModelDriven 的模型里,是通过“装配拦截器”装配的。只要我们在装配拦截器执行前,改变 ModelDriven 里的模型对象就行了。这就需要我们自定义一个拦截器,struts2 提供了这个机制。在自定义的拦截器里,我们根据用户调用的 Action 方法,新建一个模型,并且将模型设置到 Action 中,这样模型就可以是动态的了,记住,这个拦截器需要放在 defaultStack 的前面。

同样,新的问题是如何根据 Action 方法动态的选择业务模型呢?难道重复的写 if 方法吗?当然不能这样,动态的模型,就应该来自于动态的方法。因此定义的 action 方法需要有规约,笔者在自己的程序中,是这样定义规约的。Action 方法是这样组成:_$_,使用美元符隔开(美元符是 Java 方法合法的标识符),前部分是操作名,可以任意取,后部分是业务模型的类名。同时,所有的业务模型,都放到指定的一个包里,假设该包名为 com.dw.business。那么在自定义的拦截里,我们获得用户调用的 Action 方法名,按美元符隔开获得后半部分的类名,指定的包名(这里是 com.dw.business)+ 类名就是业务模型类的全路径,使用 Java 反射机制动态生成一个空的业务模型对象(所以,业务模型类必须有一个无参的构造函数),设置到 Action 里,再交给装配器的时候,装配器会自动组装这个模型。该拦截器的核心代码如清单 4 所示。


清单 4. 拦截器清单
				 
 public String intercept(ActionInvocation ai) throws Exception {
		ai.addPreResultListener(this);
	Main action = (Main)ai.getAction();
	//业务方法名
	String name = ai.getInvocationContext().getName();
	int lastIndex = name.lastIndexOf("$");
	if (lastIndex != -1)
	{
	  try {
		String head = "com.dw.business.";
		String className = name.substring(lastIndex+1, name.length());
		//关键:动态设置业务模型
		action.setModel(Class.forName(head).newInstance());
	    } catch (Exception e) {}
	}
	return ai.invoke();
}


有了上面的配置,基本可以做到屏蔽大多数技术细节开发了,但是我们还有一个问题,当在业务方法中,意外抛出了异常,struts2 默认的是返回 INPUT,按照 清单 1 的配置,发生错误将跳转到 noDir/error.jsp 页面,显示错误信息,这适合在非 Ajax 的处理。但是有时候我们希望他返回错误是 JSON 类型,因为 Action 的一些方法是 Ajax 的调用方式,也就是 Action 方法的执行结果需要返回 errorJson。我的解决方法是利用 Java 注解技术,定义一个新的注解,名为 IfErrorReturnToJson,它的代码如清单 5 所示。


清单 5. IfErrorReturnToJson 的代码
				 
 @Target(ElementType.METHOD) 
 @Retention(RetentionPolicy.RUNTIME) 
 public @interface IfErrorReturnToJson { 

 } 

该注解作用在方法上,也就是 Action 的业务方法,如果我们希望某业务方法在发送错误时,就返回 JSON 类型,那么我们只需要在该方法上加上这个注解。现在,我们如何动态的修改返回值呢。清单 2 的第二行,为 ActionInvocation 添加了 PreResultListener,这个监听器是在返回结果前进行一些处理,正符合我们的需求。我们为自定义拦截器类实现了 PreResultListener 接口,实现了接口方法,如清单 6 所示。


清单 6. PreResultListener 的代码
				 
public void beforeResult(ActionInvocation ai, String result) {
		
	if (Main.INPUT.equals(result) || Main.ERROR.equals(result))
	{
		try {
			String methodName = ai.getInvocationContext().getName();
			Method method = Main.class.getMethod(methodName);
			if (method != null && method.getAnnotation(
			        IfErrorReturnToJson.class) != null)
			{
					ai.setResultCode(Main.ERROR_JSON);
			}
		} catch (Exception e) {
		}
	}
} 


可以看到,我们在返回结果前,如果当前的返回结果是 INPUT 或者 ERROR,我们会使用反射机制,检查该方法是否加了 IfErrorReturnToJson 的注解,如果加了注解,则调用 ai.setResultCode(Main.ERROR_JSON); 方法,修改返回值,使得结果为 JSON 数据类型。


事务隔离级别的规约

在 SSH 开发中,需要重点考虑的是 Spring 的事务配置。根据不同的业务,定义的事务隔离级别就不同,比如对隔离级别要求高的,就要用到 Spring 的序列化读的隔离配置;有一些方法只是为了权限控制,用于页面跳转,则不需要用到事务控制;一些操作目的是搜索,那么该事务就是只读的。精细的事务配置,可以提高业务处理的代码效率。这时候,业务方法的命名规约就可以起到隔离级别的控制作用,比如方法名是 *begin*( 方法名中包含 begin),则该方法没有事务控制;方法名是 *search* 的,则该方法拥有只读的事务;方法名是 *seri*,则用序列化读事务控制,提高并发安全级别。这个事务配置清单如所示。


权限规约

在一些应用中,涉及到简单的权限管理。读者可能会想到一些开源的中间件,如 ralasafe 这样的开源权限组件,虽然很全面,但是学习起来需要一定的时间,熟练掌握,并配合 SSH 开发则更需要细致的学习。当我们只是简单的权限控制时,我们完全可以用到一些规约,来完成用户的权限控制。在我设计的规约中,需要在数据库中定义一张 Permission 表,代表权限 , 它与用户表是多对一的关系,它至少有两个字段,一个是 permissionName,一个是 permissionPrefix。permissionName 用于描述该权限,而 permissionPrefix 是我们所关心的。我们设计 Action 的方法,遵守 permissionPrefix_actionMethodName$BussinessBean 这样的原则,permissionPrefix 前缀代表数据库中权限表的 permissionPrefix 值 , 使用下划线隔开。当用户登录后,会将该用户所拥有的权限列表存放到 session 之中。当用户试图访问一个 Action Method 时,会使用 ModelDriven 的规约 里一样的方法,截取方法名获得该方法允许的访问权限,如果用户的权限列表中包含了该方法的权限,则允许调用,否则不允许调用。这样设计,虽然无法做到数据的访问权限,却可以满足一大部门的功能权限控制。这里需要记住,权限描述可以修改,但是权限的 permissionPrefix 不能修改,如果方法名中没有权限标识,则代表任何用户都可以访问。类似的,如果一个方法多个权限都可以访问,则可以这样设计方法 p1_p2_p3_methodName$BussinessBean,使用多个下划线分割。


合理利用 Struts2 的传参技术

基于 HTTP 协议的特殊性,上传到 Web 服务器的数值都是字符串,而我们的业务模型都是对象类型,有一些还是复杂的业务对象。Struts2 提供了 Conveter 的机制,允许程序员将 String 转换成复杂的业务对象。但是笔者刚用这个机制的时候,开始的确兴奋,但是随着业务的修改,业务模型的修改,这些 Conveter 的管理着实让人头疼。因此,本人认为 Conveter 技术应该尽量少用。我提出了一个新的方法,假设一个业务模型中,里面包含一个 List<People> pids 属性对象,People 里有一个 id 属性,我们需要客户端上传 People 的 id 列表,放入 List<People> pids 之中。如果使用 Conveter,我们在客户端需要定义规则,如客户端上传 pids=1,2,3,4,6,8。然后服务器端使用 Conveter 执行分割字符串、新建 People 对象、设置 ID、添加到列表等一系列操作。听着都头晕不是吗 ? 而且这相对并不安全,对程序员解析字符串的功底要求很高。我们感谢 Struts2 的传参机制,如果我们这样传参:<input name=”pids[0].id”/><input name=”pids[1].id”/>。这两个 input 的上传,Struts2 会根据上传数据的 name,自动组装成 List<People> 对象,并且赋值给 pids,pids[0] 代表列表的第 0 个元素,这用到了 OGNL 表达式的传参规则,它会自动识别 pids 是数组还是列表,如果 pids 默认是空,它还会自动新建一个空的数组或列表。笔者可以查看 OGNL 的相关教程。合理利用该技术,可以大大缩减传参的难度。


合理使用 Struts2 的标签

Struts2 提供了众多的标签,这些标签大致包括了 UI 标签、数据标签以及逻辑标签。这里,我们需要理解 UI 标签与服务器端的数据交互格式,比如 checkboxlist 标签,传到服务器端就是一个数组,该数组存放的是选定的 checkbox 列表的数值 , 这比使用 iterator 标签生成 checkbox 列表容易获得数据。Doubleselect 标签,用于生成 2 级的级联 select,经常使用的是部门 - 用户的级联。Optiontransferselect 标签,用于批量的迁移,比如用于批量的为部门分配用户。使用 struts2 的标签可以大大减少用户界面的开发,以及使得用户界面到服务器的数据传输方式变得非常简单。


Action 的模型验证

Struts2 具有一套完善的验证机制,在 ActionSupport 类里,可以将模型验证方法写在 validate* 方法里。如果重写了 ActionSupport 的 validate 方法,这个 validate 会在执行所有 Action Method 前调用,执行验证。而自定义的 validate*(* 是方法名),比如方法名是 add,则这个方法名就是 validateAdd),它只会在执行 add 方法前执行验证。对于数据的验证,笔者建议使用 validater 文件验证,它更加容易配置和修改,利用现有的验证器,可以减少硬编码验证的痛苦。在上面提到的框架中,由于使用的是动态方法机制,我们需要在 Action 类所在的包里,新建 validator 的 XML 文件,名字是 { 类名 }-{ 方法名 }-validation.xml(如果不是动态的方法,则 { 类名 }-validation.xml 就足够了)。最后的结果如图 2 所示。


图 2. Validator 文件配置结果
图 2. Validator 文件配置结果 

具体的配置内容,读者可以搜索 Struts2 的 validation 框架教程。


自定义业务模型验证器

Struts2 提供的验证器,包括 date、required、requiredstring 等等,这些可以归于数据验证。而对于特定的业务模型验证,则比较复杂,因此,在该框架中,可以自定义一个业务验证器,这是 struts2 支持的,它负责对业务模型进行验证,比如可以验证用户上传的用户 ID 的用户是否存在,这可以在很大程度上保证系统的安全性。验证器的代码清单 7 如下面所示。


清单 7. 业务验证器代码
				 
 public class BusinessValidator extends FieldValidatorSupport {

	private String property = null;
	
	public String getProperty() {
		return property;
	}
	
	public void setProperty(String property) {
		this.property = property;
	}
	
	@Override
	public void validate(Object exist) throws ValidationException {
		String fieldName = getFieldName();
		Object fieldValue = getFieldValue(fieldName, exist);
		if (fieldValue != null && fieldValue instanceof Integer && 
		((Integer)fieldValue) <= 0)
		{
			addFieldError("message", "上传的ID,该数据是不存在!");
		} else if (fieldValue == null)
		{
			addFieldError("message", "上传的ID,该数据是不存在!");
		} else {
			if (exist != null && exist instanceof Main && 
			((Main)exist).getModel() instanceof IChecker)
			{
				Main pa = (Main)exist;
				IChecker e = (IChecker)pa.getModel();
				boolean isRight = e.checkOk(property, pa);
				if (!isRight)
				{
					addFieldError("message", "上传的ID,该数据是不存在!");
				} else {
					pa.getPubDao().getHibernateTemplate().clear();
				}
			}
		}
	}
} 


清单 7 中,用到一个 IChecker 接口,需要验证的业务模型需要实现 IChecker 接口,在接口实现方法中实现业务验证过程,错误的话返回 false。

在 src 目录(或者 WEB-INF 下的 class 目录),添加 validater.xml 文件,在其他自带的验证器后,添加业务验证器配置,命名为 check。


清单 8. 验证器的配置
				 
 <validators> 
    ……
    <validator name="check" class="com.attendance.action.BusinessValidator"/> 
 </validators> 

接下来就可以使用这个验证器,在图 2 中的 validation 文件里,添加如清单 9 的配置。


清单 9. 验证器的使用
				 
 <field-validator type="check" short-circuit="true"> 
 <param name="property">department</param> 
 <message> 该部门不存在 !</message> 
 </field-validator> 


利用 JEE Eclipse 生成 Hibernate 的 JPA 模型

IBM 提供了 JEE 版的 Eclipse,专门用于开发 Java EE 的应用,它提供了从数据库中生成符合 JPA 规范的数据模型的能力。Hibernate3 以后,支持了 JPA 规范(不是完全支持,但是已经较为全面),利用 JEE Eclipse 的生成能力,就可以避免繁琐的 hbm 文件的配置。同时,JPA 的规范里,还可以提供 NamedQuery、OrderBy 等注解,对于复杂的数据库,该规范可以减少开发时间。


UI 重用

Struts2 的 action 标签,用于调用某个 action。这个标签笔者认为非常有用,尤其体现在 UI 重用中,比如用户管理中,在很多个界面里,都允许用户信息修改和用户删除,那么我们就可以将用户信息修改和用户删除的页面代码以及 JavaScript 放在一个 JSP 里,同时定义一个 Action 方法 ( 名为 A),为这个 JSP 执行初始化。接下来在允许进行用户修改和删除的界面,都用 s:action 标签调用这个 A 方法,设置 executeResult 为 true,将用户修改和删除的代码包含在页面里。这样就实现了 Action 的重用。如果重用的界面不需要服务器的初始化,这直接使用 jsp:include 或 s:include 引用重用的 JSP。


小结

本文通过一系列的讲解,讲述了如何搭建一个通用的 SSH 开发框架,陈述了其中的设计思想,由于篇幅限制,文章只介绍了框架中的重要部分和重要思想,希望读者可以从中获益。由于笔者水平有限,如有错误,请联系我批评指正。

Spring+Struts2+Hibernate+MySQL框架整合开发完整的java WEB增删改查实例 使用的Spring+Struts2+Hibernate+MySQL数据库实现增删改查完整的Web 开发环境:MyEclipse10,+JDK1.6,+Windows操作系统,MySQL数据库, 立即下载

相关推荐

FPGA学习之路—应用程序—原码二位乘法器及Verilog代码分析

FPGA学习之路——原码二位乘法器及Verilog代码分析 原理 原码乘法可以分为原码一位乘和原码二位乘,两者在实现规则上大同小异。原码一位乘每次判断乘数的最低位,对被乘数和部分积进行相应操作。而原码二位乘则是对乘数的低二位进行判断,并执行相关操作。 两位乘数的取值可以有四种可能组合,每种组合对应于以下操作: 00相当于0x,部分积Dresult右移2位,不进行其他运算; 01相当于1x,部分积D...

谦豫 3717

(IBM)Struts2、Spring、Hibernate 高效开发的最佳实践

引言 SSH(Struts2+Spring+Hibernate)是最为 Java 业界熟知的 Java EE Web 组件层的开发技术。很多人提起 Java EE,甚至都会将其误认为就是 SSH。无论是书籍还是电子教程,大部分都已经千篇一律,讲解各种标签、配置的用法。许多人包括笔者在内,第一次使用 SSH 的时候,按照教程的介绍进行开发。繁琐的配置,重复的修改配置,不断定义的参数转换器,真的让笔...

了解更多请移驾我的个人博客:www.itlanguageexpress.info 219

Windows中的TLS 1.2启用方法(IIS、C#、.Net framework)

折腾几天了windows中的tls1.2启用方法!特此记录一下 开发背景: 在一个用.net framework 2.0开发的客户端程序里面嵌入功能调用第三方物联网相关接口,服务器上有一个restful接口用于接收第三方上报的数据及处理,最后再调用第三方的物联网相关接口。本机开发环境Windows 10,客户服务器是Windows Server 2008 R2。 第一次写这种物联网相关的接口调用,而且第三方提供的文档比较简单,最基本的报文示例都没。开发环境里面各种摸索一步一个坑,首先在发送HTTP请求前

dl1314ld的博客 1万+

若依自动生成模板格式

【代码】若依自动生成模板格式。

yqj234的专栏 191

鸿蒙OS开机动画背后的秘密:从代码到视觉的完整解析(附源码分析)

本文深入解析了鸿蒙OS开机动画的系统级实现原理。从bootanimation服务的启动配置、与Render Service的协同,到基于VSync信号的帧率同步与绘制流水线,结合OpenHarmony源码进行了逐行解读。文章揭示了其事件驱动的优雅退出机制,并探讨了视频支持、多屏适配等高级特性与定制化可能,为开发者理解鸿蒙图形子系统提供了硬核技术视角。

sony5的博客 974

第二十七届华东杯数学建模A 题 跳台滑雪问题 完整思路模型及代码

考虑到滑行过程中的空气阻力和摩擦力对速度的影响,我们引入了不同姿态下运动员迎风面积和空气阻力系数的变化,利用牛顿第二定律建立加速度表达式,并通过数值模拟比较常见姿态下的终端速度。针对问题二,我们构建了二维空中飞行动力学模型,结合起跳速度、身体迎角、滑雪板倾角等因素,模拟运动员在空中飞行的轨迹与姿态变化,采用欧拉法对运动过程进行仿真,优化飞行路径和稳定性。仿真结果表明,运动员应在起跳后保持滑雪板与身体成“V”字形打开、重心略后倾的姿态,以增强升力、延长飞行距离并提高姿态得分。,并模拟出跳跃的轨迹和最终得分。

lichensun的博客 3210

JEESITE快速开发平台(七)代码生成原理

一、原理讲解 jeesite代码生成用的是FreeMarker模板引擎结合xml技术来实现的,定义的模板都放在resources/templates/modules/gen下 一看就知道crud就是基本的增删改查,dao是数据库操作,treetable是有关树方面的模板,其中主要的配置文件就是config.xml,该文件中定义了生成的模板,以及java类型,查询类型,字段...

小桥Dopey的博客 625

CANoe: Panel的上位机控制方法

本文介绍了不同于IG的报文控制方法,实现了Panel面板的控制模式。

Jonsnow3zz的博客 1410

Spring+Struts2+Hibernate整合开发讲解

Spring框架学的差不多了,现在开始做项目了。今天老师给我们讲了讲如何用Spring+Struts2+Hibernate进行整合开发。下面我就说说如何进行开发! 第一步:创建一个web项目,需要引入类库文件; 你项目中需要什么jar就引入什么jar,(别忘了引入数据库的jar包)如图大概就是这些jar包: 二、添加配置文件 1、struts2的配置文件(struts2的配置文件名

xueshuangshuang123的专栏 1416

Python 爬虫实战:微博自动化运营工具(点赞 / 转发 / 评论 + 反封号策略)

微博作为中国最大的社交媒体平台之一,拥有庞大的用户群体和丰富的数据资源。通过 Python 爬虫技术,我们可以实现微博的自动化运营,包括点赞、转发、评论等功能,同时采取有效的反封号策略,确保账号的安全和稳定运行。

u014481728的博客 1179

PINN:当深度学习遇上朗伯-比尔定律

光谱数据处理中引入PINN的三种架构设计

qq_53529450的博客 154

spring + struts2 + hibernate环境搭建

1、开发环境 笔者采用的开发平台为myeclipse10,spring-3.0,hibernate-3.3,struts-2.1。 2、环境搭建 (1)在myeclipse创建Web Project项目,项目名为SSHTest,如下图所示。 图 1 图 2 图 3 此时,一个简单的web项目就创建好了,现在,在项目里面没有SSH框架,这可以通过myeclipse自

qinghunya的专栏 4408

多体动力学分析软件:SIMPACK_(17).SIMPACK高级编程与脚本

自定义力和约束可以用于模拟更复杂和现实的物理场景。SIMPACK 提供了接口,允许用户通过 Python 脚本来实现自定义力和约束。以下是一个示例,展示如何定义一个自定义力函数并应用于模型。# 定义自定义力函数"""自定义力函数:param t: 时间:param position: 位置:param velocity: 速度:return: 力"""# 创建一个新的 SIMPACK 模型# 添加一个刚体# 添加一个关节# 添加一个自定义力# 设置仿真参数# 运行仿真。

kkchenjj的博客 1424

struts2、Spring、Hibernate 高效开发的最佳实践

杨 硕, 研究生, 东北大学 魏 强, 研究生, 东北大学 刘 强, 工程师, 中科院沈阳计算所 简介: Struts2、Spring、Hibernate(SSH)是最常用的 Java EE Web 组件层的开发技术搭配,网络中和许多 IT 技术书籍中都有它们的开发教程,但是通常的教程都会让很多程序员陷入痛苦的配置与修改配置的过程。本文利用 SSH 中的技术特性,利用 Java 反射技术,按

HeroW的专栏 1075

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Struts2,spring,hibernate高效开发的最佳实践

简介: Struts2、Spring、Hibernate(SSH)是最常用的 Java EE Web 组件层的开发技术搭配,网络中和许多 IT技术书籍中都有它们的开发教程,但是通常的教程都会让很多程序员陷入痛苦的配置与修改配置的过程。本文利用 SSH中的技术特性,利用 Java 反射技术,按照规约优于配置的原理,基于 SSH设定编写了一个通用开发框架,这使得开发者可以专注于业务逻辑的开发,

yj_021219的专栏 793

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Struts2、Spring、Hibernate 高效开发的最佳实践(转)

  引言 SSH(Struts2+Spring+Hibernate)是最为 Java 业界熟知的 Java EE Web 组件层的开发技术。很多人提起 Java EE,甚至都会将其误认为就是 SSH。无论是书籍还是电子教程,大部分都已经千篇一律,讲解各种标签、配置的用法。许多人包括笔者在内,第一次使用 SSH 的时候,按照教程的介绍进行开发。繁琐的配置,重复的修改配置,不断定义的参数转换器,真...

anlystar 164

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

[转] Struts2、Spring、Hibernate 高效开发的最佳实践

FROM:http://www.ibm.com/developerworks/cn/java/j-lo-ssh/ 简介:Struts2、Spring、Hibernate(SSH)是最常用的 Java EE Web 组件层的开发技术搭配,网络中和许多 IT 技术书籍中都有它们的开发教程,但是通常的教程都会让很多程序员陷入痛苦的配置与修改配置的过程。本文利用 SSH 中的技术...

weixin_38166789的博客 66

Struts2、Spring、Hibernate 高效开发的最佳实践(转载)

Struts2、Spring、Hibernate 高效开发的最佳实践 Struts2、Spring、Hibernate(SSH)是最常用的 Java EE Web 组件层的开发技术搭配,网络中和许多 IT 技术书籍中都有它们的开发教程,但是通常的教程都会让很多程序员陷入痛苦的配置与修改配置的过程。本文利用 SSH 中的技术特性,利用 Java 反射技术,按照规约优于配置的原理,基...

weixin_33688840的博客 108

Struts2+Spring+Hibernate 高效开发的最佳实践 S2SH

引言 SSH(Struts2+Spring+Hibernate)是最为 Java 业界熟知的 Java EE Web 组件层的开发技术。很多人提起 Java EE,甚至都会将其误认为就是 SSH。无论是书籍还是电子教程,大部分都已经千篇一律,讲解各种标签、配置的用法。许多人包括笔者在内,第一次使用 SSH 的时候,按照教程的介绍进行开发。繁琐的配置,重复的修改配置,不断定义的参数转换器,真的

Nacey 1018
上一篇: struts2 valuestrack 原理
下一篇: hibernate.jdbc.fetch_size 和 hibernate.jdbc.batch_size 作用
dw_java08
博客等级 码龄15年 122粉丝 66原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值