框架 day39-42 SSH整合练习项目CRM(配置文件,增删改查,ajax,上传/下载,分页,BaseDao/Action)

1     配置文件

1.1   spring配置

1.1.1       介绍

    加载properties

    配置数据源DataSource

    配置SessionFactory , 加载所有hbm.xml

    hibernate事务管理

    使用 <import > 所有的模块都使用单独配置文件

框架 day39-42 SSH整合练习项目CRM(配置文件,增删改查,ajax,上传/下载,分页,BaseDao/Action)_第1张图片        

1.1.2       使用源码包

    使用config源码,将源码和配置文件分开存放,方便程序的维护。

框架 day39-42 SSH整合练习项目CRM(配置文件,增删改查,ajax,上传/下载,分页,BaseDao/Action)_第2张图片        

 

1.1.3       spring核心

1.1.3.0约束

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       					   http://www.springframework.org/schema/beans/spring-beans.xsd
       					   http://www.springframework.org/schema/tx 
       					   http://www.springframework.org/schema/tx/spring-tx.xsd
       					   http://www.springframework.org/schema/aop 
       					   http://www.springframework.org/schema/aop/spring-aop.xsd
       					   http://www.springframework.org/schema/context 
       					   http://www.springframework.org/schema/context/spring-context.xsd">


1.1.3.1    加载properties

	<!-- 公共配置文件,web.xml配置加载核心文件 -->
	<!-- 1 加载properties文件 -->
	<context:property-placeholder location="classpath:jdbcinfo.properties"/>

1.1.3.2    配置数据源

	<!-- 2 配置数据源 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="${jdbc.driverClass}"></property>
		<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
		<property name="user" value="${jdbc.user}"></property>
		<property name="password" value="${jdbc.password}"></property>
	</bean>

1.1.3.3    配置hibernate sessionFactory

	<!-- 3 配置hibernate SessionFactory -->
	<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
		<!-- 3.1 配置数据源 
			* <property name="属性名" ref="另一个bean引用">
				name 必须是对象的setter方法推断获得,setDataSource(...), 去掉set DataSource ,首字母小写  dataSource
			* ref 其他bean引用 <bean id=""> 可以任意,一般情况与上面属性名称相同。
		-->
		<property name="dataSource" ref="dataSource"></property>
		<!-- 3.2 配置hibernate其他属性 
			* 在hibernate.cfg.xml 配置文件 “hibernate.dialect” 和 “dialect” 等效的
			* 在spring配置文件中,必须使用“hibernate.dialect”
		-->
		<property name="hibernateProperties">
			<props>
				<!-- 方言 -->
				<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
				<!-- 显示sql语句 -->
				<prop key="hibernate.show_sql">true</prop>
				<!-- 格式化sql语句 -->
				<prop key="hibernate.format_sql">true</prop>
			</props>
		</property>
		<!-- 3.3 加载映射文件 
			com/itheima/crm/staff/domain/CrmStaff.hbm.xml
			com/itheima/crm/post/domain/CrmPost.hbm.xml
			com/itheima/crm/*/domain/*.hbm.xml
		-->
		<property name="mappingLocations" value="classpath:com/itheima/crm/*/domain/*.hbm.xml"></property>
	</bean>


1.1.3.4    配置 hibernate 事务管理

	<!-- 4 事务管理 -->
	<!-- 4.1 事务管理器,spring事务必须在事务管理器平台上工作 
		* 在hibernate中事务需要session,session是从sessionFactory中获取的。
	-->
	<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
	<!-- 4.2 事务通知,确定事务的详情,明确切入点使用什么样的事务  
		* 项目约定:service层方法名称
			所有添加必须add开头
			所有更新必须update开头
			所有删除必须delete开头
			所有查询必须find开头
	-->
	<tx:advice id="txAdvice" transaction-manager="txManager">
		<tx:attributes>
			<tx:method name="add*"/>
			<tx:method name="save*"/>
			<tx:method name="update*"/>
			<tx:method name="delete*"/>
			<tx:method name="find*" read-only="true"/>
			<tx:method name="*" read-only="true"/>
		</tx:attributes>
	</tx:advice>
	<!-- 4.3 aop编程,确定切入点  
		* 所有的service层,需要进行事务管理
			com.itheima.crm.staff.service.impl
			com.itheima.crm.classes.service.impl
			com.itheima.crm.*.service..
	-->
	<aop:config>
		<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.crm.*.service..*.*(..))"/>
	</aop:config>

 

1.2   struts配置

    在struts.xml 配置“公共模块”,使用include包含子模块,所有的子模块都继承“公共模块”

框架 day39-42 SSH整合练习项目CRM(配置文件,增删改查,ajax,上传/下载,分页,BaseDao/Action)_第3张图片

struts.xml

<struts>
	<!-- struts 核心配置,公共内容 -->
	<!-- 1 常量 -->
	<!-- 1.1 开发模式 -->
	<constant name="struts.devMode" value="true"></constant>
	<!-- 1.2 struts 标签主题, simple 表示 没有风格,使用struts标签为了回显 -->
	<constant name="struts.ui.theme" value="simple"></constant>
	<!-- 2 公共模块,共有的内容都配置此包中 -->
	<package name="common" namespace="/" extends="struts-default">
	</package>
	<!-- 包含其他模块 -->
	<include file="struts/struts-staff.xml"></include>
</struts>

struts-staff.xml

<struts>
	<!-- 每一个模块 # 单独配置员工 , 所有的模块将使用“struts.xml.公共模块”-->
	<package name="crm_sta" namespace="/staff" extends="common">
	</package>
</struts>


1.3   web.xml配置

<!-- spring  
  	* 设置初始化参数,确定spring配置文件位置
  	* 使用监听器去加载配置文件,并将spring容器存放到ServletContext作用域
  -->
  <context-param>
  	<param-name>contextConfigLocation</param-name>
  	<param-value>classpath:spring/applicationContext.xml</param-value>
  </context-param>
  <listener>
  	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <!-- struts  
  	* 配置前端控制器,服务器在启动时,初始化init(FilerConfig)将自动调用
  	* struts在初始化方法中,将自动的加载 classpath:struts.xml 文件  (src/config 两个源码目录都表示 类路径 classpath)
  -->
  <filter>
  	<filter-name>struts2</filter-name>
  	<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>struts2</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>


 

2     用户登录


框架 day39-42 SSH整合练习项目CRM(配置文件,增删改查,ajax,上传/下载,分页,BaseDao/Action)_第4张图片

    编写PO类(已经实现)

    dao执行用户查询(用户名和密码)

       继承 HibernateDaoSupport,需要spring注入SessionFactory

    service事务管理(已经实现)

       注意:dao和service实现,需要配置到 applicationContext_staff.xml

    action

       1获得数据

              属性驱动--action属性 (<input name="username" />  --> action 类  setUsername(String username) )

              属性驱动--javabean (<inputname="user.username">  --> action类  setUesr(User user))

              模型驱动 ModelDriven  (1.实现接口  2编写javabean实例(new) 3 实现getModel方法并返回实例)

       2.使用service 进行登录

       3.处理信息

              登录成功: session作用域记录登录状态,重定向登录成功页

              不成功:当前请求记录错误信息(request作用域),使用请求转发,在登录页面显示

       注意:action 需要配置到 struts-staff.xml

 

    规定:所有的jsp页面(除登录页)存在WEB-INF下,javaee规范规定,浏览器端不能直接访问WEB-INF目录下的内容(tomcat直接过滤掉了),使用请求转发(<resulttype="dispatcher">)在服务器内部完成使用java程序读取内容,没有限制。

 

2.1   dao

    dao实现 必须继承 HibernateDaoSupport

    使用HibernateTemplate 提供find查询所有

public class StaffDaoImpl extends HibernateDaoSupport implements StaffDao {

	@Override
	public CrmStaff find(CrmStaff staff) {
		List<CrmStaff> list = this.getHibernateTemplate()
			.find("from CrmStaff where loginName = ? and loginPwd = ?"
				, staff.getLoginName(),staff.getLoginPwd());
		if(list != null && list.size() > 0){
			return list.get(0);
		}
		return null;
	}

	@Override
	public List<CrmStaff> findAll(String condition, Object[] params) {
		String hql = "from CrmStaff where 1=1 " + condition;
		return this.getHibernateTemplate().find(hql , params);
	}

}

 

2.2   service(MD5加密)

    登录员工密码需要使用MD5加密

public class StaffServiceImpl implements StaffService {

	private StaffDao staffDao;
	public void setStaffDao(StaffDao staffDao) {
		this.staffDao = staffDao;
	}
	
	@Override
	public CrmStaff login(CrmStaff staff) {
		//登录密码需要加密
		staff.setLoginPwd(MyStringUtils.getMD5Value(staff.getLoginPwd()));
		return staffDao.find(staff);
	}

}
MD5加密Utils
public class MyStringUtils {

	/**
	 * 将提供的数据进行md5加密
	 * * 理论上不可逆的
	 * * JDK提供工具进行 消息摘要算法(加密)
	 * @param value
	 * @return
	 */
	public static String getMD5Value(String value){
		try {
			//1 获得工具类
			MessageDigest messageDigest = MessageDigest.getInstance("MD5");
			//2 加密,加密结果为10进制
			byte[] md5ValueByteArray = messageDigest.digest(value.getBytes());
			//3 将10机制转换成16进制
			BigInteger bigInteger = new BigInteger(1 ,  md5ValueByteArray);
			//4 转换
			return bigInteger.toString(16);
		} catch (Exception e) {
			//如果有异常,不加密
			return value;
		}
	}

}


 

2.3   配置spring

	<!-- 员工配置文件,一般情况:service、dao -->
	
	<!-- 1 dao -->
	<bean id="staffDao" class="com.itheima.crm.staff.dao.impl.StaffDaoImpl">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
	<!-- 2 service -->
	<bean id="staffService" class="com.itheima.crm.staff.service.impl.StaffServiceImpl">
		<property name="staffDao" ref="staffDao"></property>
	</bean>


2.4   登录页面

    首页:使用forward包含登录页

<jsp:forwardpage="/WEB-INF/pages/login.jsp"></jsp:forward>

    登录页,将html表单,使用struts标签进行修改

 

2.5   action编写

2.5.1       封装数据

    实现Model接口

	//1 封装数据
	private CrmStaff staff = new CrmStaff(); //1.2 提供javabean实例(一定要new)
	@Override
	public CrmStaff getModel() {	//1.3 实现方法
		return staff;
	}



2.5.2       提供service setter方法

    action提供service属性名,必须与spring配置 service名称一致的

	//2 spring 自动按照名称进行注入
	// 2.1 员工service
	// 2.1 员工service
	private StaffService staffService;
	public void setStaffService(StaffService staffService) {
		this.staffService = staffService;
	}
	// 2.2部门service
	private DepartmentService departmentService;
	public void setDepartmentService(DepartmentService departmentService) {
		this.departmentService = departmentService;
	}
	// 2.3 职务
	private PostService postService;
	public void setPostService(PostService postService) {
		this.postService = postService;
	}


2.5.3       登录

    getSession().put() 相当于添加session作用域

    addFieldError给指定的标签设置错误提示信息,标签的主题为simple,信息将不显示,需要使用在jsp<s:fieldEroor> 显示所有

    this.addActionMessage()  jsp 显示  <s:actionMessage> (可选)

	public String login(){
		
		// 登录
		CrmStaff loginStaff = staffService.login(staff);
		// 处理
		if(loginStaff != null){
			//登录成功 -- session作用域数据,重定向首页
			ActionContext.getContext().getSession().put("loginStaff", loginStaff);
			return "success";
		} else {
			//不成功 -- 登录页给出提示
			this.addFieldError("", "登录用户和密码不匹配");
			return "login";
		}
	}


 

2.5.4       登录成功

    显示WEB-INF目录下页面

	/**
	 * 登录成功页面
	 * @return
	 */
	public String home(){
		return "home";
	}

 

2.6   action配置

<struts>
	<!-- 每一个模块 # 单独配置员工 , 所有的模块将使用“struts.xml.公共模块”-->
	<package name="crm_sta" namespace="/staff" extends="common">
		<action name="staffAction_*" class="com.itheima.crm.staff.web.action.StaffAction" method="{1}">
			<!-- 1 登录成功 ,重定向 成功页(action)
				dispatcher ,默认值,请求转发到jsp
				redirect,重定向到jsp
				redirectAction,重定向到另一个action
				chain,链 请求转发到另一个action
			-->
			<result name="success" type="redirectAction">staffAction_home</result>
			<!-- 2 login 在登录页中显示信息 
			<result name="login">/WEB-INF/pages/login.jsp</result>
			-->
			<!-- 3 成功页面 -->
			<result name="home">/WEB-INF/pages/frame.jsp</result>
			<!-- 4 input 用于处理系统默认错误 -->
			<result name="input">/WEB-INF/pages/login.jsp</result>
			<!-- 5 查询所有 -->
			<result name="findAll">/WEB-INF/pages/staff/listStaff.jsp</result>
		</action>
	</package>
</struts>


 

2.7   UIAction

    思想:如何统一显示WEB-INF目录下的jsp页面?

    在struts.xml 编写共有内容

		<!-- 2.1 UIAction统一显示 WEB-INF下的jsp页面
			# uiAction_*_* , 第一个星表示文件夹名称,第二个星表示jsp文件文件
			# class 默认值 ActionSupport
				1) struts-default.xml
					<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
				2) actionSupport 默认方法和返回值
					public String execute() throws Exception {
				        return SUCCESS;
				    }
			# result.name 默认值 success
		
		 -->
		<action name="uiAction_*_*">
			<result>/WEB-INF/pages/{1}/{2}.jsp</result>
		</action>


3     拦截器


    编写登录拦截器,除了登录功能,其他的页面必须登录才能访问

    拦截器编写:

       1.编写实现类

              功能:判断session是否保存登录用户信息,如果没有拦截,如果有放行。

       2.配置拦截器

              2.1将自定义拦截器注册给struts

              2.2使用自定义拦截器,排除登录功能。

    实现类回顾

        

       Interceptor接口规定拦截器(1初始化、2拦截、3销毁),必须编写3个方法

       AbstractInterceptor拦截器抽象实现类,只需要编写“拦截”方法即可

       MethodFilterInterceptor方法过滤拦截器,使用此拦截器,在配置拦截器可以设置不需要拦截的方法。

 

    http://localhost:8080/crm/index.jsp  当访问首页时,不使用自定义拦截器栈。

       原因:struts 拦截器 值拦截action,不拦截jsp。

 

3.1   实现类

    继承 MethodFiledInterceptor 可以在配置文件中设置需要过滤的方法,多个方法使用逗号分隔。

//登录拦截器
public class LoginInterceptor extends MethodFilterInterceptor {
	
	/*
	private String methodName;
	public void setMethodName(String methodName) {
		this.methodName = methodName;
	}
	*/

	@Override
	protected String doIntercept(ActionInvocation invocation) throws Exception {
		/*
		String method = invocation.getProxy().getMethod();
		if(methodName.equals(method)){
			//放行
			return invocation.invoke();
		}
		*/
		
		//判断用户登录状态
		Object loginStaff = ActionContext.getContext().getSession().get("loginStaff");
		if(loginStaff == null){
			/**友好提示 start*/
			Object action = invocation.getAction();
			if(action instanceof ActionSupport){
				ActionSupport actionSupport = (ActionSupport) action;
				actionSupport.addFieldError("", "请登录");
			}
			/**友好提示 end*/
			//没有登录
			return "login";
		}
		//放行
		return invocation.invoke();
	}

}


3.2   配置拦截器

    将自定义拦截器,与struts 默认拦截器栈 组合成一个新的栈

    将自定义拦截器栈,配置自定义默认拦截器栈

<!-- 2.2 拦截器 -->

		<!-- 2.2 拦截器 -->
		<interceptors>
			<!-- 2.2.1 注册拦截器(名称和实现类) -->
			<interceptor name="loginInterceptor" class="com.itheima.crm.web.interceptor.LoginInterceptor"></interceptor>
			<!-- 2.2.2 自定义拦截器栈 -->
			<interceptor-stack name="crmStack">
				<!-- 1) 默认拦截器栈 -->
				<interceptor-ref name="defaultStack"></interceptor-ref>
				<!-- 2) 其他拦截器(token令牌:重置表单重复提交) -->
				<!-- 3) 自定义拦截器 
					* 设置<param name="属性"> 将执行拦截器实现类的setter方法
						<param name="methodName">login</param>
					* excludeMethods 给父类设置需要排除的方法们,多个方法使用逗号分隔
				-->
				<interceptor-ref name="loginInterceptor">
					<param name="excludeMethods">login</param>
				</interceptor-ref>
			</interceptor-stack>
		</interceptors>
		
		<!-- 2.2.3 将自定义栈 配置 默认栈 
		<default-interceptor-ref name="crmStack"></default-interceptor-ref>
		-->


3.3   扩展

手动编写拦截器忽略方法见实现类代码/**/注释内容


3.4   配置全局结果

    登录拦截器,将拦截所有内容,如果没有登陆,大家共用一个result,需要配置全局结果。

		<!-- 2.2.4 全局结果 -->
		<global-results>
			<result name="login">/WEB-INF/pages/login.jsp</result>
		</global-results>

 

4     校验器


    编程式:在action 编写

       所有方法:必须实现接口Validateable ,实现方法 invalidate()方法,校验所有的方法

       单个方法:必须实现接口Validateable ,编写特殊的方法 invalidateAdd() 方法,表示值校验add方法

    声明式:使用xml配置的

       所有方法:

              文件名称:action类名-validation.xml

       单个方法:

              1)文件名称:action类名-action配置名称-validation.xml

                     例如:http://localhost:8080/crm/staff/staffAction_login.action

                                          action配置名称 -->  staffAction_login

                     实例:对login方法校验,StaffAction-staffAction_login-validation.xml

              2)文件约束

xwork-core-2.3.15.3.jar/xwork-validator-1.0.3.dtd

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
  		"-//Apache Struts//XWork Validator 1.0.3//EN"
  		"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>

</validators>


              3)文件内容

                     类型:xwork-core-2.3.15.3.jar/com/opensymphony/xwork2/validator/validators/default.xml

<validators>
	<!-- 1 登录用户 -->
	<field name="loginName">
		<!-- 1.1 必填 -->
		<field-validator type="requiredstring">
			<message>登录用户名不能为空</message>
		</field-validator>
		<!-- 1.2 长度-->
		<field-validator type="stringlength">
			<param name="maxLength">14</param>
			<param name="minLength">2</param>
			<message>登录用户名必须在${minLength}-${maxLength}字符之间</message>
		</field-validator>
	</field>
	<!-- 登录密码 -->
	<!-- 1 登录用户 -->
	<field name="loginPwd">
		<!-- 1.1 必填 -->
		<field-validator type="requiredstring">
			<message>登录密码不能为空</message>
		</field-validator>
		<!-- 1.2 长度-->
		<field-validator type="stringlength">
			<param name="maxLength">16</param>
			<param name="minLength">4</param>
			<message>登录密码必须在${minLength}-${maxLength}字符之间</message>
		</field-validator>
	</field>
</validators>


              4)文件位置,与action类同包

                      

5     员工管理--查询所有


5.1   dao层

	@Override
	public List<CrmStaff> findAll() {
		return this.getHibernateTemplate().find("from CrmStaff");
	}

5.2   service层

	@Override
	public List<CrmStaff> findAll() {
		return staffDao.findAll();
	}

 

5.3   action实现及配置

    /crm/src/com/itheima/crm/staff/web/action/StaffAction.java

<!-- 5 查询所有 -->

<resultname="findAll">/WEB-INF/pages/staff/listStaff.jsp</result> 

	/**
	 * 查询所有
	 * @return
	 */
	public String findAll(){
		// 查询
		List<CrmStaff> allStaff = staffService.findAll();
		// 将查询结果存放 值栈中 -- root  --> jsp页面获取,  key 或 属性名  获得内容
		// * 如果一组数据(List) ,使用root set方法 ,设置key
		// * 如果一个对象(javabean),使用root push方法 ,javabean属性
		ActionContext.getContext().getValueStack().set("allStaff", allStaff);
		
		return "findAll";
	}

配置结果

<!-- 5 查询所有 -->
<result name="findAll">/WEB-INF/pages/staff/listStaff.jsp</result>
 

5.4   OpenSessionInViewFilter

框架 day39-42 SSH整合练习项目CRM(配置文件,增删改查,ajax,上传/下载,分页,BaseDao/Action)_第5张图片

    在web.xml 必须spring提供过滤器,必须放置struts过滤器之前

  <!-- spring  提供过滤器 -->
  <filter>
  	<filter-name>openSession</filter-name>
  	<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>openSession</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>


 

5.5   员工管理--条件查询

5.5.1       查询所有部门

5.5.1.1    dao层

5.5.1.2    service层

5.5.1.3    配置spring

 

5.5.2       通过部门id查询职务

5.5.2.1    dao层

5.5.2.2    service层

5.5.2.3    spring 配置

5.5.3       优化

    在web.xml中配置加载所有spring文件

applicationContext*.xml  使用*通配符

  <context-param>
  	<param-name>contextConfigLocation</param-name>
  	<param-value>classpath:spring/applicationContext*.xml</param-value>
  </context-param>

    注意:applicationContext.xml 不需要配置 <import>

        

5.5.4       发送ajax进行查询职务

    使用ajax发送部门的id,查询对应的所有的职务

       /crm/post/postAction_findAllWithDepartment?crmDepartment.depId=

    将查询的结果转成成json数据,使用javascript遍历数据并展示。

       使用Jsonlib 将 List<CrmPost>转成字符串

 

5.5.4.1    发送ajax

	<script type="text/javascript">
		function showPost(obj) {
			//1 获得选中的部门id
			var depId = obj.value;
			//2 发送ajax数据,通过部门的id查询职务
			// * 路径参考 /crm/post/postAction_findAllWithDepartment?crmDepartment.depId=
			// 2.1 创建对象(ajax引擎)
			var xmlhttp = null;
			if (window.XMLHttpRequest){
				xmlhttp=new XMLHttpRequest();
			} else if (window.ActiveXObject){
				xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
			}
			// 2.2 设置回调
			xmlhttp.onreadystatechange = function(){
				if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
					// # 获得select对象
					var selectObj = document.getElementById("postSelectId");
					selectObj.innerHTML = "<option value=''>--请选择职务--</option>";
					//1)获得数据(字符串)
					var data = xmlhttp.responseText;
					//2) 转成json对象
					var jsonData = eval("("+data+")");
					//3)遍历
					for(var i = 0 ; i < jsonData.length ; i ++){
						var postObj = jsonData[i];
						// 3.1)获得id
						var postId = postObj.postId;
						// 3.2)获得名称
						var postName = postObj.postName;
						
						// #添加数据
						selectObj.innerHTML += "<option value='"+postId+"'>"+postName+"</option>";
						
					}
				}
			};
			// 2.3 建立连接
			var url = "${pageContext.request.contextPath}/post/postAction_findAllWithDepartment?crmDepartment.depId=" + depId;
			xmlhttp.open("get",url);
			// 2.4 发送请求
			xmlhttp.send(null);
			
		}
	</script>

5.5.4.2    action生成json数据

    使用jsonlib 需要导入jar包

 

/**
	 * ajax 通过部门id查询职务,发送json
	 * @return
	 * @throws IOException 
	 */
	public String findAllWithDepartment() throws IOException{
		//1 查询
		List<CrmPost> allPost = postService.findAll(post.getCrmDepartment().getDepId());
		
		//2 jsonlib 将指定数据转发json字符串
		//JSONObject 处理java对象 (map、javabean)
		//JSONArray 处理java容器(数组、List、Set)
		// 2.1 排除不需要字段
		JsonConfig jsonConfig = new JsonConfig();
		jsonConfig.setExcludes(new String[] {"crmDepartment","crmStaffs"});
		// 2.2 转换
		String jsonStr = JSONArray.fromObject(allPost,jsonConfig).toString();
		
		// 2.3 将json数据发送给浏览器
		ServletActionContext.getResponse().setContentType("application/json;charset=UTF-8");
		ServletActionContext.getResponse().getWriter().print(jsonStr);
		
		return NONE; //表示没有返回值
	}

 

5.5.5       条件查询实现

    使用ognl表达式串联进行数据封装,通过staff一个可以获得需要的所有数据。

    根据staff进行条件查询

    staff被 ModelDriven拦截器已经压入到栈顶,struts标签回显时,从栈顶开始获得数据,如果有就回显。

 

5.5.5.1    jsp表单

奇偶样式

    	<%--遍历数据,奇偶行样式不同   
    		class="tabtd1" ,class="tabtd2"
    	--%>
    <s:iterator value="allStaff" status="vs">  <%--将遍历每一项压入到栈顶(root),可以通过javabean 属性获得值 --%>
	  <tr class="<s:property value="#vs.odd ? 'tabtd1' : 'tabtd2' "/>"> 

ajax双select联动显示

框架 day39-42 SSH整合练习项目CRM(配置文件,增删改查,ajax,上传/下载,分页,BaseDao/Action)_第6张图片 

 

5.5.5.2    action实现类

 

	/**
	 * 查询所有
	 * @return
	 */
	public String findAll(){
		// 1 查询所有员工
		// 查询
		List<CrmStaff> allStaff = staffService.findAll(staff);
		// 将查询结果存放 值栈中 -- root  --> jsp页面获取,  key 或 属性名  获得内容
		// * 如果一组数据(List) ,使用root set方法 ,设置key
		// * 如果一个对象(javabean),使用root push方法 ,javabean属性
		ActionContext.getContext().getValueStack().set("allStaff", allStaff);
		
		//2 查询所有的部门
		List<CrmDepartment> allDepartment = this.departmentService.findAll();
		// * 将数据存放到context  , jsp获取 “#key”
		ActionContext.getContext().put("allDepartment", allDepartment);
		//3 如果选中部门,将查询部门的所有的职务
		String depId = null;
		if(staff.getCrmPost() != null && staff.getCrmPost().getCrmDepartment() != null){
			depId = staff.getCrmPost().getCrmDepartment().getDepId();
			if(StringUtils.isNotBlank(depId)){
				//选中部门
				List<CrmPost> allPost = postService.findAll(depId);
				ActionContext.getContext().getValueStack().set("allPost", allPost);
			}
		}
		return "findAll";
	}

框架 day39-42 SSH整合练习项目CRM(配置文件,增删改查,ajax,上传/下载,分页,BaseDao/Action)_第7张图片

 

5.5.5.3    service

    使用 StringBuilder 拼凑 HQL语句,条件中都是“ and  属性 符号 ?” 在最后使用  “where 1=1 ”

    List拼凑实际参数,(有序,可重复)

	@Override
	public List<CrmStaff> findAll(CrmStaff staff) {
		//拼凑条件
		//* 条件
		StringBuilder sqlBuilder = new StringBuilder();
		//* 参数
		List<Object> paramsList = new ArrayList<Object>();
		
		//有可能有条件
		if(staff.getCrmPost() != null){
			//2  选择职务(有职务就不添加部门)
			if(StringUtils.isNotBlank(staff.getCrmPost().getPostId())){
				sqlBuilder.append(" and crmPost = ?");
				paramsList.add(staff.getCrmPost());
			} else {
				//1 选中部门
				CrmDepartment department = staff.getCrmPost().getCrmDepartment();
				if(department != null && StringUtils.isNotBlank(department.getDepId())){
					sqlBuilder.append(" and crmPost.crmDepartment = ?");
					paramsList.add(staff.getCrmPost().getCrmDepartment());
				}
			}
		}		
		//3员工姓名 null  ""
		if(StringUtils.isNotBlank(staff.getStaffName())){
			sqlBuilder.append(" and staffName like ?");
			paramsList.add("%"+staff.getStaffName()+"%");
		}
		
		// 将转成需要数据
		String condition = sqlBuilder.toString();
		Object[] params = paramsList.toArray();
	
		return staffDao.findAll(condition , params);
	}

 

6     课程类别


6.1   dao层

    所有的dao继承 HibernateDaoSupport ,通过底层创建HibernateTemplate 进行PO操作。

    save添加、update更新、delete删除

    find查询所有,get |load 通过id查询

public class CourseTypeDaoImpl extends HibernateDaoSupport implements CourseTypeDao {

	@Override
	public void save(CrmCourseType courseType) {
		this.getHibernateTemplate().save(courseType);
	}

	@Override
	public void update(CrmCourseType courseType) {
		this.getHibernateTemplate().update(courseType);
	}

	@Override
	public void delete(CrmCourseType courseType) {
		this.getHibernateTemplate().delete(courseType);
	}

	@Override
	public List<CrmCourseType> findAll() {
		return this.getHibernateTemplate().find("from CrmCourseType");
	}

	@Override
	public CrmCourseType findById(String id) {
		return this.getHibernateTemplate().get(CrmCourseType.class, id);
	}

}

 

6.2   service层

    提供 service 层 主要用于事务管理和业务处理。

 

6.3   配置spring

 

6.4   查询所有

6.4.1       action实现

 

6.4.2       struts配置

    注意:将单独文件需要添加到 struts.xml中

 

6.4.3       jsp遍历

  <%--数据展示,单行:tabtd1;双行:tabtd2 --%>
  <%--如果使用var,将查询结果存放context key=var value=遍历某一项 ,标签体中获取的方式 “#key” 
  	* 注意:如果使用var iterator迭代 在context存放一份,也在root中也存放一份。
  --%>
  <s:iterator value="data" var="courseType">  
   <tr class="tabtd1">
	    <td align="center"><s:property value="#courseType.courseName" /></td>
	    <td align="center"><s:property value="#courseType.remark" /></td>
	    <td align="center"><s:property value="#courseType.total" /></td>
	    <td align="center"><s:property value="#courseType.courseCost" /></td>
	  	<td width="11%" align="center">
	  		
	  		<s:a namespace="/courseType" action="courseTypeAction_addOrUpdateUI">
	  			<s:param name="courseTypeId" value="#courseType.courseTypeId"></s:param>
	       		<img src="${pageContext.request.contextPath}/images/button/modify.gif" class="img" />
    		</s:a>
	  	</td>
	  </tr>
  </s:iterator>


 

6.5   添加和更新(saveOrUpdate)

    hibernate提供saveOrUpdate 保存或更新。

       代理主键:(hibernate自动设置)

              如果没有OID,将执行save

              如果有OID,将执行update

       自然主键:(手动设置)

              执行之前必须查询select

              如果查询没有结果,将执行save

              如果查询有结果,将执行update

    添加 jsp页面没有id值,表达没有数据

    更新 jsp页面需要id值,提供hidden 隐藏域存放id值。需要通过id查询标签回显(struts标签)

 

6.5.1       dao

@Override
	public void saveOrUpdate(CrmCourseType courseType) {
		this.getHibernateTemplate().saveOrUpdate(courseType);
	}


6.5.2       service

@Override
	public void saveOrUpdateCourseType(CrmCourseType courseType) {
		this.courseTypeDao.saveOrUpdate(courseType);
	}

6.5.3       action

    需要提供UI显示页面,需要通过id查询

 

	/**
	 * 添加或编辑 页面显示
	 * @return
	 */
	public String addOrUpdateUI(){
		//如果有id表示更新 -- 通过id查询类别
		if(StringUtils.isNotBlank(courseType.getCourseTypeId())){
			// 通过id查询
			CrmCourseType findCourseType = courseTypeService.findById(courseType.getCourseTypeId());
			// 必须将对象压入到指定
			ActionContext.getContext().getValueStack().push(findCourseType);
		}
		
		return "addOrUpdateUI";
	}

	/**
	 * 添加或更新操作
	 * @return
	 */
	public String addOrUpdate(){
		courseTypeService.saveOrUpdateCourseType(courseType);
		return "addOrUpdate";
	}


6.5.4       struts配置

			<!-- 添加或更新成功 ,重定向查询
				* 给结果类实现类设置属性值
			-->
			<result name="addOrUpdate" type="redirectAction">
				<param name="namespace">/courseType</param>
				<param name="actionName">courseTypeAction_findAll</param>
			</result>

6.5.5       jsp表单

    更新时,需要提供隐藏域,此处必须使用if语句。如果没有添加 courseTypeId="" 不能添加成功

<s:form namespace="/courseType" action="courseTypeAction_addOrUpdate">
	
	<%--提供隐藏域,更新时使用 --%>
	<s:if test="courseTypeId != null">
		<s:hidden name="courseTypeId"></s:hidden>
	</s:if>

 

6.6   分页 + 条件

    将使用自定义javabean封装分页的数据

PageBean

public class PageBean<T> {
	//必须
	private int pageNum;		//当前页(第几页)
	private int pageSize;		//每页显示数据
	private int totalRecord;	//总记录数
	//计算
	private int startIndex;		//开始索引
	private int totalPage;		//总页数
	//分页结果
	private List<T> data;	//分页数据
	
	// 动态显示导航条
	private int start;
	private int end;
	
	
	public PageBean(int pageNum, int pageSize, int totalRecord) {
		super();
		this.pageNum = pageNum;
		this.pageSize = pageSize;
		this.totalRecord = totalRecord;
		
		//1 算法:开始索引
		this.startIndex = (this.pageNum - 1) * this.pageSize;
		//2 算法:总页数
		this.totalPage = (this.totalRecord + this.pageSize - 1) / this.pageSize;
		
		//3 处理导航条 (显示10个分页)
		this.start = 1;
		this.end = 10;
		
		// totalPage = 4;
		if(this.totalPage <= 10){
			this.start = 1;
			this.end = this.totalPage;
		} else {
			// totalPage = 38 ,要求:前4后5
			
			this.start = this.pageNum - 4;
			this.end = this.pageNum + 5;
			
			// 第一页
			if(this.start < 1){
				this.start = 1;
				this.end = 10;
			}
			
			// 最后一页
			if(this.end > this.totalPage){
				this.end = this.totalPage;
				this.start = this.totalPage - 9;
			}
			
		}
		
	}
	
get set...............	
	
	


PageHibernateCallBack hql 分页查询回调

public class PageHibernateCallBack<T> implements HibernateCallback<List<T>> {
	
	private String hql;			//hql语句
	private Object[] params;	//hql对应实际参数
	private int firstResult;	//开始索引
	private int maxResults;		//每页显示个数
	
	public PageHibernateCallBack(String hql, Object[] params, int firstResult,
			int maxResults) {
		super();
		this.hql = hql;
		this.params = params;
		this.firstResult = firstResult;
		this.maxResults = maxResults;
	}



	@Override
	public List<T> doInHibernate(Session session) throws HibernateException,
			SQLException {
		//1 创建Query对象
		Query queryObject = session.createQuery(hql);
		//2 设置实际参数
		if (params != null) {
			for (int i = 0; i < params.length; i++) {
				queryObject.setParameter(i, params[i]);
			}
		}
		//3 分页
		// 3.1 开始索引
		if (firstResult >= 0) {
			queryObject.setFirstResult(firstResult);
		}
		// 3.2 每页显示个数
		if (maxResults > 0) {
			queryObject.setMaxResults(maxResults);
		}
		return queryObject.list();
	}

}


 

6.6.1       分页

    service层将 web层传递(pageNum,pageSize)进行处理并封装到PageBean中,需要查询总记录

		//1 总记录数
		int totalRecord = this.courseTypeDao.getTotalRecord(condition,params);
		
		//2 将查询结果封装 javabean
		PageBean<CrmCourseType> pageBean = new PageBean<CrmCourseType>(pageNum, pageSize, totalRecord);
		
		//3 查询分页数
		List<CrmCourseType> data = this.courseTypeDao.findAll(condition,params, pageBean.getStartIndex(), pageSize);
		pageBean.setData(data);
		
		return pageBean;


6.6.2       条件查询(拼凑条件)

    查询总记录时,需要传递条件

    查询分页数据时,也需要传递条件

    在service拼凑条件即可。

	@Override
	public PageBean<CrmCourseType> findAll(CrmCourseType courseType, int pageNum,
			int pageSize) {
		//拼凑条件
		//#1 准备对象
		StringBuilder builder = new StringBuilder();
		List<Object> paramsList = new ArrayList<Object>();
		//#2 拼凑
		//#2.1 类别名称 
		if(StringUtils.isNotBlank(courseType.getCourseName())){
			builder.append(" and courseName like ? ");
			paramsList.add("%"+courseType.getCourseName()+"%");
		}
		//#2.2 简介
		if(StringUtils.isNotBlank(courseType.getRemark())){
			builder.append(" and remark like ? ");
			paramsList.add("%"+courseType.getRemark()+"%");
		}
		//#2.3 总学时--条件都是字符串,需要的整形
		int totalStart = 0;
		int totalEnd = 0;
		if(StringUtils.isNotBlank(courseType.getTotalStart())){  //200
			totalStart = Integer.parseInt(courseType.getTotalStart());
		}
		if(StringUtils.isNotBlank(courseType.getTotalEnd())){   //100
			totalEnd = Integer.parseInt(courseType.getTotalEnd());
		}
		// * 处理start <= end
		int temp = 0;
		if(totalStart > totalEnd){
			/*
			totalStart = totalStart + totalEnd;
			totalEnd = totalStart - totalEnd;
			totalStart = totalStart - totalEnd;
			*/
			temp = totalStart;
			totalStart = totalEnd;
			totalEnd = temp;
			//查询条件中没有交换
		}
		// * 拼凑sql
		if(totalStart > 0){
			builder.append(" and total >= ?");
			paramsList.add(totalStart);
		}
		
		if(totalEnd > 0){
			builder.append(" and total <= ?");
			paramsList.add(totalEnd);
		}
		
		//#2.4 费用
		if(StringUtils.isNotBlank(courseType.getLessonCostStart())){
			builder.append(" and courseCost >= ?");
			paramsList.add(Double.parseDouble(courseType.getLessonCostStart()));
		}
		if(StringUtils.isNotBlank(courseType.getLessonCostEnd())){
			builder.append(" and courseCost <= ?");
			paramsList.add(Double.parseDouble(courseType.getLessonCostEnd()));
		}
		
		//#3 转换
		String condition = builder.toString();
		Object[] params = paramsList.toArray();
		
		
		
		//1 总记录数
		int totalRecord = this.courseTypeDao.getTotalRecord(condition,params);
		
		//2 将查询结果封装 javabean
		PageBean<CrmCourseType> pageBean = new PageBean<CrmCourseType>(pageNum, pageSize, totalRecord);
		
		//3 查询分页数
		List<CrmCourseType> data = this.courseTypeDao.findAll(condition,params, pageBean.getStartIndex(), pageSize);
		pageBean.setData(data);
		
		return pageBean;
	}


 

6.6.3       jsp处理

    使用javascript,将分页的数据,与表单中条件数据 一并发送给服务器

    或分页a标签一并把条件发送过去

 


分页jsp

<table border="0" cellspacing="0" cellpadding="0" align="center">
  <tr>
    <td align="right">
    	<span>第<s:property value="pageNum"/>/<s:property value="totalPage"/>页</span><br/>
        <span>
        <s:if test="pageNum>1">
        	<s:a namespace="/courseType" action="courseTypeAction_findAll">[首页]
        		<s:param name="pageNum" value="1"></s:param>
        	</s:a>          	
        	<s:a namespace="/courseType" action="courseTypeAction_findAll">[上一页]
        		<s:param name="pageNum" value="pageNum-1"></s:param>
        	</s:a>    
        </s:if>
        <!-- 1234..分页条 --> 
        <s:iterator begin="start" end="end" var="m">
        	<s:a namespace="/courseType" action="courseTypeAction_findAll">
        		<s:property value="#m"/>
        		<s:param name="pageNum" value="#m"></s:param>
        	</s:a> 
        </s:iterator>
        <s:if test="pageNum<totalPage">
        	<!--        
            <s:a namespace="/courseType" action="courseTypeAction_findAll">[下一页]
            	<s:param name="pageNum" value="pageNum+1"></s:param>
            </s:a>   
            --> 
            <!-- 分页使用JS将分页与条件一并提交表单 ↓-->
            <a href="javascript:void(0)" onclick="condition(<s:property value="pageNum+1"/>)">[下一页]</a>  
            <!-- 分页使用JS将分页与条件一并提交表单↑ -->     
            <s:a namespace="/courseType" action="courseTypeAction_findAll">[尾页]
            	<s:param name="pageNum" value="totalPage"></s:param>
            </s:a> 
         </s:if>          
        </span>
    </td>
  </tr>
</table>
<!-- hiddenId -->
</body>
<script type="text/javascript">
	function condition(pageNum){
		//<s:hidden name="pageNum" id="hiddenId"></s:hidden>
		//将表单隐藏标签(pageNum)value赋值
		document.getElementById("hiddenId").value=pageNum;
		//点击onclick提交  连接提交为<a href="javascript:void(0)"
		document.forms[0].submit();
		
	}
</script>



7     编写BaseDao和BaseAction


    泛型 + 反射

Dao层一般情况下,进行增删改查(CRUD)

添加:session.save(PO)

修改:session.update(PO)

删除:session.delete(PO)

添加或更新:session.saveOrUpdate(PO)

OID查询:session.get(Xxx.class,id)  / session.load(Xxx.class,id)

HQL查询:session.createQuery(hql).list()


 分析:BaseDao 使用接口

框架 day39-42 SSH整合练习项目CRM(配置文件,增删改查,ajax,上传/下载,分页,BaseDao/Action)_第8张图片

 

7.1   提供统一接口BaseDao

public interface BaseDao<T> {
	/**
	 * 保存
	 * @param t
	 */
	public void save(T t);
	/**
	 * 更新
	 * @param t
	 */
	public void update(T t);
	/**
	 * 删除
	 * @param t
	 */
	public void delete(T t);
	/**
	 * 保存或更新
	 * @param t
	 */
	public void saveOrUpdate(T t);
	/**
	 * 通过id查询
	 * @param t
	 */
	public T findById(String id);
	/**
	 * 查询所有
	 * @param t
	 */
	public List<T> findAll();
	/**
	 * 查询带有条件所有
	 * @param t
	 */
	public List<T> findAll(String hqlCondition,Object[] params);
	
	
	/**
	 * 查询总记录数,带有条件
	 * @param hqlCondition
	 * @param hqlParams
	 * @return
	 */
	int findTotalRecord(String hqlCondition, Object[] hqlParams);

	/**
	 * 查询带有条件,分页数据
	 * @param hqlCondition hql查询条件
	 * @param hqlParams 对应的实际参数
	 * @param startIndex 开始索引
	 * @param pageSize 每页显示个数
	 * @return
	 */
	List<T> findAll(String hqlCondition, Object[] hqlParams,
			int startIndex, int pageSize);

}


 

7.2   提供实现BaseDaoImpl

    BaseDao的实现,继承HibernateDaoSupport

 

public class BaseDaoImpl<T> extends HibernateDaoSupport implements BaseDao<T> {
	
	//具体操作PO类Class对象
	private Class<T> beanClass;
	//具体操作PO类 全限定类名
	private String className;
	
	public BaseDaoImpl() {
		//1 获得当前运行类的,具有泛型信息的父类,
		ParameterizedType parameterizedType =  (ParameterizedType) this.getClass().getGenericSuperclass();
		//2 获得实际参数类型
		beanClass = (Class)parameterizedType.getActualTypeArguments()[0];
		//3 实际参数类型 全限定类名
		className = beanClass.getName();
	}

	@Override
	public void save(T t) {
		this.getHibernateTemplate().save(t);
	}

	@Override
	public void update(T t) {
		this.getHibernateTemplate().update(t);
	}

	@Override
	public void delete(T t) {
		this.getHibernateTemplate().delete(t);
	}
	@Override
	public void saveOrUpdate(T t) {
		this.getHibernateTemplate().saveOrUpdate(t);
	}

	@Override
	public T findById(String id) {
		return this.getHibernateTemplate().get(beanClass, id);
	}

	@Override
	public List<T> findAll() {
		return this.getHibernateTemplate().find("from " + className);
	}

	@Override
	public List<T> findAll(String hqlCondition, Object[] params) {
		String hql = "from " +className + " where 1=1 " + hqlCondition;
		return this.getHibernateTemplate().find(hql, params);
	}

	@Override
	public int findTotalRecord(String hqlCondition, Object[] hqlParams) {
		String hql = "select count(*) from " + className + " where 1=1 " + hqlCondition;
		List<Long> list = this.getHibernateTemplate().find(hql, hqlParams);
		return list.size() == 1 ? list.get(0).intValue() : 0 ;
	}

	@Override
	public List<T> findAll(String hqlCondition, Object[] hqlParams,
			int startIndex, int pageSize) {
		String hql = "from "+className+" where 1=1 " + hqlCondition;
		return this.getHibernateTemplate().execute(new PageHibernateCallback<T>(hql, hqlParams, startIndex, pageSize));
	}

}


 

7.3   使用

7.3.1       接口

 

public interface UserDao extends BaseDao<CrmUser> {

	/**
	 * 使用用户名和密码进行查询/特有方法
	 * @param logonName
	 * @param logonPwd 注意:密码需要MD5加密
	 * @return
	 */
	public CrmUser findUser(String logonName,String logonPwd);
	
}

7.3.2       实现类

 

public class UserDaoImpl extends BaseDaoImpl<CrmUser> implements UserDao {

	@Override
	@SuppressWarnings("unchecked")
	public CrmUser findUser(String logonName, String logonPwd) {
		List<CrmUser> allUser = this.getHibernateTemplate()
.find("from CrmUser c where c.logonName = ? and c.logonPwd = ?" ,logonName,logonPwd);
		return allUser.size() == 1 ? allUser.get(0) : null ;
	}
}

BaseAction

public class BaseAction<T> extends ActionSupport implements ModelDriven<T> {
	
	// 0 使用反射,实例化 T
	public BaseAction() {
		try {
			//1 获得当前运行类,被参数化父类。例如:BaseAction<CrmClass>
			ParameterizedType parameterizedType = (ParameterizedType) this
					.getClass().getGenericSuperclass();
			//2 获得具体类型, CrmClass ,获得第一个实际参数
			// * 泛型可以有多个,所以提供的是数组获得。例如: AClass<A,B,C,D,E>
			@SuppressWarnings("unchecked")
			Class<T> crmClass = (Class<T>) parameterizedType.getActualTypeArguments()[0];
			//3 实例化  new CrmClass();
			t = crmClass.newInstance();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		
	}
	
	//1 封装数据
	private T t;
	@Override
	public T getModel() {
		return t;
	}
	
	//2 注入使用到service(如果都存放父类,之后将越来越多,可以采取放置在子类中)
	//2.1
	private ClassesService classesService;
	// ** 交予spring注入
	public void setClassesService(ClassesService classesService) {
		this.classesService = classesService;
	}
	// ** 提供给子类调用

	
	
	//3 分页数据
	private int pageNum;
	private int pageSize = 2;		//暂时固定的
	public void setPageNum(int pageNum) {
		this.pageNum = pageNum;
	}
	
	
	//4 简化 值栈操作
	// 4.1 root --set 
	public void set(String key,Object o){
		ActionContext.getContext().getValueStack().set(key, o);
	}
	// 4.2 root -- push
	public void push(Object o){
		ActionContext.getContext().getValueStack().push(o);
	}
	// 4.3 context
	public void put(String key,Object value){
		ActionContext.getContext().put(key, value);
	}
	// 4.4 context -- session
	public void putSession(String key,Object value){
		ActionContext.getContext().getSession().put(key, value);
	}

}


 

8文件上传


框架 day39-42 SSH整合练习项目CRM(配置文件,增删改查,ajax,上传/下载,分页,BaseDao/Action)_第9张图片

1.1   jsp页面

    提供 <input type="file" name="xxx">

    表单 <form method="post"enctype="multipart/form-data">

 

 

1.2   action提供属性

    struts默认拦截器栈中 提供upload拦截器,完成文件上传功能。

       提供特定的属性即可

       Filexxx; 内容

       StringxxxFileName; 名称

       StringxxxContentType; 类型

    action实例默认压入到栈顶的,如果使用ModelDriven javabean再压入

 

/**
	 * 上传页面
	 * @return
	 */
	public String uploadUI(){
		//通过id查询班级
		CrmClass findClass = this.getClassesService().findById(this.getModel().getClassId());
		//压入栈顶
		this.push(findClass);
		return "uploadUI";
	}
	
	private File schedule;				//文件内容
	private String scheduleFileName;	//文件名称
	private String scheduleContentType;	//文件类型(没有用)
	public void setSchedule(File schedule) {
		this.schedule = schedule;
	}
	public void setScheduleFileName(String scheduleFileName) {
		this.scheduleFileName = scheduleFileName;
	}
	public void setScheduleContentType(String scheduleContentType) {
		this.scheduleContentType = scheduleContentType;
	}
	/**
	 * 文件上传
	 * @return
	 */
	@InputConfig(resultName="uploadInput")  //如果不使用注解,方法出错时,默认返回input
	public String upload(){
		try {
			//将 文件保存硬盘中 -- 将课表的内容保存硬盘,文件名随机,没有扩展名 (及将一个文件拆分两部分:内容,文件名)
			//1 上传文件父目录 WEB-INF/upload
			String parentDir = ServletActionContext.getServletContext().getRealPath("/WEB-INF/upload");
			String filePath = UUID.randomUUID().toString();
			//2 保存文件
			FileUtils.copyFile(schedule, new File(parentDir , filePath));
			
			//3 保存
			this.getClassesService().addUploadFile(this.getModel().getClassId() , filePath, scheduleFileName);
			
			return "upload";
		} catch (IOException e) {
			e.printStackTrace();
			return ERROR;
		}
	}

      

1.3   拦截器属性设置

    通过给upload拦截器设置内容,确定上传文件允许扩展名

    格式:<param name="拦截器.属性">.....</param>

    		<interceptor-ref name="crmStack">
    			<!-- 设置上传文件的扩展名 -->
    			<param name="fileUpload.allowedExtensions">.xls,.xlsx</param>
    		</interceptor-ref>
     

1.4   修改错误是结果集返回值

    当程序出现错误时,workflow拦截器默认将返回input

    在目标方法 添加注解 @InputConfig(resultName="xxxxx") 确定当前方法出错时的返回名称

@InputConfig(resultName="uploadInput")  //如果不使用注解,方法出错时,默认返回input

        

9文件下载



1.5   action提供属性

    action提供 struts 获得数据,必须提供getter 方法 

	//下载资源
	private InputStream target;
	public InputStream getTarget() {
		return target;
	}
	//下载文件名,存在中文乱码
	private String downloadFileName;
	public String getDownloadFileName() throws UnsupportedEncodingException {
		// 处理中文乱码
		if(downloadFileName != null){
			return new String(downloadFileName.getBytes("GBK"),"ISO-8859-1");
		}
		return downloadFileName;
	}
	public String download(){
		//1 通过id查询
		CrmClass findClass = this.getClassesService().findById(this.getModel().getClassId());
		//2 读取内容
		InputStream is = ServletActionContext.getServletContext().getResourceAsStream("/WEB-INF/upload/" + findClass.getUploadPath());
		if(is != null){
			target = is;
			downloadFileName = findClass.getUploadFileName();
			return "download";
		}
		this.addFieldError("", "下载资源不存在");
		return "error";
	}


1.6   xml配置获得内容

    		<!-- 下载 -->
    		<result name="download" type="stream">
    			<!-- 设置响应头 -->
    			<param name="contentDisposition">attachment;filename=${downloadFileName}</param>
    			<!-- 确定流 -->
    			<param name="inputName">target</param>
    		</result>

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Web,ssh,crm,笔记)