1. Dao层编写
1) Dao层接口
登录功能即在数据库中查找有无该员工,即:
public interface StaffDao { /** * 通过用户名和密码查询 * @param loginName * @param loginPwd * @return */ public CrmStaff find(String loginName, String loginPwd); }
2) Dao层实现类
由于采用Hibernate,故实现类继承HibernateDaoSupport类,sessionFactory在spring配置文件内已经注入。若能在数据库中根据登录名和密码找到员工则返回员工类的对象,找不到返回null。
public class StaffDaoImpl extends HibernateDaoSupport implements StaffDao { @Override public CrmStaff find(String loginName, String loginPwd) { List<CrmStaff> allStaff = this.getHibernateTemplate().find( "from CrmStaff where loginName=? and loginPwd=?", loginName,loginPwd); if (allStaff.size() > 0) { return allStaff.get(0); } return null; } }
注意点:
- 按条件查询函数find(String sql, Object args..),返回List集合
2. Service层编写
1) Service层接口
登陆功能,返回员工类对象,方便存入session域中
public interface StaffService { public CrmStaff login(CrmStaff staff); }
2) Service层实现类
Service层一般还要对数据进行一些处理,这里对密码进行了MD5加密,即数据库内存储的密码非明文密码。
在Service层有Dao层对象,但不能new出来,而是要写出其set方法以使spring可以为其注入。
public class StaffServiceImpl implements StaffService{ private StaffDao staffDao; public void setStaffDao(StaffDao staffDao) { this.staffDao = staffDao; } @Override public CrmStaff login(CrmStaff staff) { String loginPwd = MyStringUtils.getMD5Value(staff.getLoginPwd()); return staffDao.find(staff.getLoginName(), loginPwd); } }
这里使用了自定义的MD5加密方法,封装在MyStringUtils里
public static String getMD5Value(String value) { try { //1 获得jdk提供的消息摘要算法工具类 MessageDigest messageDigest = MessageDigest.getInstance("MD5"); //2 加密 byte[] md5ValueByteArray = messageDigest.digest(value.getBytes()); //3 将10进制转化为16进制 BigInteger bigInteger = new BigInteger(1, md5ValueByteArray); return bigInteger.toString(16); } catch (NoSuchAlgorithmException e) { return value; }
3. Spring配置
在applicationContext-staff.xml中添加配置
<!-- 员工配置项 --> <bean id="staffDao" class="com.web.crm.staff.dao.StaffDaoImpl"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <bean id="staffService" class="com.web.crm.staff.service.impl.StaffServiceImpl"> <property name="staffDao" ref="staffDao"></property> </bean>
4. 修改登陆表单
注意点:
- 所有的jsp页面都应放在WEB-INF下,这样就无法通过浏览器直接访问,因为struts拦截器只拦截action而不拦截页面。
使用struts标签修改form表单,这样可以回显
<s:form namespace="/" action="staffAction_login"> <img src="${pageContext.request.contextPath}/images/title.png" width="185" height="26"/> <br/> <font color="#ff0000"> <!-- 错误回显 --> <s:fielderror></s:fielderror> </font> <br/> 用户名:<s:textfield name="loginName" cssClass="msg"></s:textfield><br/><br/> 密 码:<s:password name="loginPwd" cssClass="msg"></s:password><br/><br/> <s:submit value="登陆" cssClass="btn"></s:submit> </s:form>
5. 编写Action实现类
不同的模块在不同的Action类里写,这里员工登陆新建一个StaffAction实现类,其父类为ActionSupport,并实现ModelDriven接口以实现从页面传来的参数自动封装。这里的写法都是固定的:
public class StaffAction extends ActionSupport implements ModelDriven<CrmStaff> { //封装数据,这里必须要new出来 private CrmStaff staff = new CrmStaff(); @Override public CrmStaff getModel() { return staff; } //默认按照名称注入 private StaffService staffService; public void setStaffService(StaffService staffService) { this.staffService = staffService; }员工登陆方法书写的思路是:数据库查询员工->返回对象不为空表示有该员工->将对象保存在session域中->重定向到首页;返回对象为空->向错误域中保存错误信息->请求转发到登陆页面
public String login() { CrmStaff crmStaff = staffService.login(staff); if (crmStaff != null) { //成功,向session域内保存登陆信息 ActionContext.getContext().getSession().put("loginStaff", crmStaff); return "success"; } //不成功 this.addFieldError("", "用户名或密码错误"); //请求转发 return "login"; }
6. 设置登陆拦截器
实际应用过程中,用户必须登陆后才能访问其他页面,如果未经登陆就访问其他action,应当有一个拦截器对其进行拦截。因此我们需要编写一个自定义拦截器,该类需要继承MethodFilterInterceptor 类,并重写其doIntercept方法:
public class LoginInterceptor extends MethodFilterInterceptor { @Override public String doIntercept(ActionInvocation invocation) throws Exception { //判断session作用域是否有用户信息,如果有放行,如果没有拦截。 Object obj = ActionContext.getContext().getSession().get("loginStaff"); if(obj == null){ /**友好信息 start*/ // 1 获得当前运行action Object action = invocation.getAction(); // 2 判断运行时是否是ActionSupport if(action instanceof ActionSupport){ ActionSupport actionSupport = (ActionSupport) action; actionSupport.addFieldError("", "请登录"); } /**友好信息 end*/ // 没有登录,需要登录 return "login"; } //登录,放行 return invocation.invoke(); } }自定义拦截器类写完后,我们需要将其配置在公共的struts.xml中:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <constant name="struts.devMode" value="true"></constant> <constant name="struts.ui.theme" value="simple"></constant> <!-- 公共项 --> <package name="common" namespace="/" extends="struts-default"> <!-- 拦截器配置 --> <interceptors> <!-- @1 声明(注册)拦截器 --> <interceptor name="loginInterceptor" class="com.web.crm.web.interceptor.LoginInterceptor"></interceptor> <!-- @2 自定义拦截器栈 --> <interceptor-stack name="loginStack"> <interceptor-ref name="defaultStack"></interceptor-ref> <!-- 自定义拦截器需要对login不拦截 --> <interceptor-ref name="loginInterceptor"> <param name="excludeMethods">login</param> </interceptor-ref> </interceptor-stack> </interceptors> <!-- @3 声明默认 --> <default-interceptor-ref name="loginStack"></default-interceptor-ref> <!-- @4 全局结果集 --> <global-results> <result name="login">/WEB-INF/pages/login.jsp</result> </global-results> <!-- 配置公共jsp访问action --> <action name="UIAction_*_*"> <result>/WEB-INF/pages/{1}/{2}.jsp</result> </action> </package> <include file="struts/struts-staff.xml"></include> </struts>
注意全局结果集的写法,对应之前Action类中login方法,若session中不存在员工对象则返回login,然后页面转发到login.jsp
在上面的xml中我们额外写了一个名为UIAction的action,这个动作的目的在于使其他jsp页面上的链接可以通过action访问到其他页面,并且必须通过拦截器,用法如:
<frameset rows="90,*" framespacing="0px" frameborder="no"> <frame src="${pageContext.request.contextPath}/UIAction_frame_top.action" scrolling="no"/> <frameset id="main" cols="170,9,*" framespacing="0px" frameborder="no" > <frameset rows="30,*,40" framespacing="0px" frameborder="no" > <frame src="${pageContext.request.contextPath}/UIAction_frame_left1.action" scrolling="no"/> <frame src="${pageContext.request.contextPath}/UIAction_frame_left.action" scrolling="no"/> <frame src="${pageContext.request.contextPath}/UIAction_frame_left2.action" scrolling="no"/> </frameset> <frame src="${pageContext.request.contextPath}/UIAction_frame_control.action" scrolling="no"/> <frame src="${pageContext.request.contextPath}/UIAction_frame_right.action" name="right" scrolling="yes"/> </frameset> </frameset>
7. 员工登陆动作的xml配置
在struts-staff.xml中添加如下配置
<package name="sta" namespace="/" extends="common"> <action name="staffAction_*" class="com.web.crm.staff.web.action.StaffAction" method="{1}"> <result name="success" type="redirectAction">staffAction_home</result> <result name="home">/WEB-INF/pages/frame.jsp</result> <result name="findAll">/WEB-INF/pages/staff/listStaff.jsp</result> <result name="editUI">/WEB-INF/pages/staff/editStaff.jsp</result> </action> </package>
注意:
- action的name我们采用通配符的方式,因此我们在调用action时实际写法为“staffAction_method”,method为我们所写的Action类中的方法,这里调用登陆的方法即为staffAction_login
至此员工登陆功能编写完毕,整个思路流程如下:
- 写Dao层,注意点是继承HibernateDaoSupport类,并注意查询语句写法。
- 写Service层,额外的功能在该层编写,如本例中的密码MD5加密。
- 配置spring对应的xml文件,即写<bean>。
- 修改jsp页面的form表单,登陆功能比较简单。
- 编写登陆的Action实现类,继承ActionSupport类并实现ModelDriven接口以实现对表单对象的自动封装,之后编写登陆方法。
- 配置struts对应的xml文件,注意通配符的写法。
- 编写登陆拦截器,自定义拦截器类并将其配置在xml中,本例写法为自定义一个拦截器栈并将其设为默认栈。