欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

S2SH整合开发——登录

程序员文章站 2022-07-14 23:42:29
...

本文用S2SH实现用户登录。

框架图

S2SH整合开发——登录
Modle层就是对应的数据库表的实体类(如User类)。

Dao层,一般可以再分为***Dao接口和***DaoImpl实现类,如userDao接口和userDaoImpl实现类,接口负责定义数据库curd的操作方法,实现类负责具体的实现,即实现Dao接口定义的方法。
一个DAO单独对1个表进行CURD/排序/分页等操作。

Service层,引用对应的Dao层数据库操作,在这里可以编写自己需要的代码(比如简单的判断),也可以再细分为Service接口和ServiceImpl实现类。
一个Service可以操作几个DAO。

Action层:引用对应的Service层实现业务逻辑,在这里结合Struts的配置文件,跳转到指定的页面,当然也能接受页面传递的请求数据,也可以做些计算处理、前端输入合法性检验(前端可修改网页绕过前端合法性检验,需在后台加一层)。

Model层开发

model层开发主要包括创建实体类及映射文件。

实体类创建

UseInfo:

package com.digital.entity;

import java.util.Date;

public class UserInfo {
    private int id;
    private String userName;
    private String password;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }


    // 无参构造
    public UserInfo() {
    }

    // 有参构造
    public UserInfo(String userName, String password, Date regDate) {
        this.userName = userName;
        this.password = password;
    }

}

创建映射文件

UserInfo.hbm.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.digital.entity">
    <class name="UserInfo" table="user_info" catalog="digital">
        <id name="id" type="java.lang.Integer">
            <column name="id" />
            <generator class="native"></generator>
        </id>
        <property name="userName" type="java.lang.String">
            <column name="userName" length="16" not-null="true" />
        </property>
        <property name="password" type="java.lang.String">
            <column name="password" length="16" not-null="true" />
        </property>
    </class>
</hibernate-mapping>

Spring与Hibernate的整合

先回顾一下Hibernate的运行过程:

  1. 通过Configuration().configure();读取并解析hibernate.cfg.xml配置文件
  2. 由hibernate.cfg.xml中的<mapping resource="xxx.hbm.xml"/>读取并解析映射信息
  3. 通过config.buildSessionFactory();//创建SessionFactory
  4. sessionFactory.openSession();//打开Sesssion
  5. session.beginTransaction();//创建事务Transation
  6. persistent operate持久化操作 //一般指Save这个方法
  7. session.getTransaction().commit();//提交事务
  8. 关闭Session

很关键的就是sessionFacctory了,Spring整合Hibernate的目的就在于用Spring的IoC容器来管理Hibrenate的SessionFactory(把它当成了一个Bean),同时让Hibernate使用Spring的声明式事务,而这些都是在spring配置文件中完成的。

applicationContext中整合Hibernate的部分:

<?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:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">      


    <!-- 配置数据源 -->
    <bean id="dataSource"  
        class="com.mchange.v2.c3p0.ComboPooledDataSource">  
        <property name="driverClass" value="com.mysql.jdbc.Driver" />  
        <property name="jdbcUrl" value="jdbc:mysql:///digital" />  
        <property name="user" value="root" />  
        <property name="password" value="admin" />   
        <property name="minPoolSize" value="5" />  
        <property name="maxPoolSize" value="10" />
    </bean>  

    <!-- 配置Hibernate的sessionFactory实例 -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <!-- 配置数据源属性 -->
        <property name="dataSource">
            <ref bean="dataSource" />
        </property>
        <!-- 配置 Hibernate的基本属性-->
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">
                    org.hibernate.dialect.MySQLDialect
                </prop>
            </props>
        </property>
        <!-- 配置 Hibernate映射文件的位置及名称-->
        <property name="mappingResources">
            <list>
                <value>com/digital/entity/UserInfo.hbm.xml</value>
            </list>
        </property>
    </bean>

    <!-- 声明Hibernate事务管理器 -->
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <!--  定义事务通知 ,需要事务管理器  --> 
    <tx:advice id="txAdvice" transaction-manager="transactionManager">   
      <!-- 指定事务传播规则 -->
      <tx:attributes>
        <!-- 对所有方法应用REQUIRED事务规则 -->
        <tx:method name="*" propagation="REQUIRED" /> 
      </tx:attributes>
    </tx:advice>

    <!--定义切面,并将事务通知和切面组合(定义哪些方法应用事务规则) -->
    <aop:config>
        <!-- 对com.digital.service包下的所有类的所有方法都应用事务规则 -->
        <aop:pointcut id="serviceMethods" expression="execution(* com.digital.service.*.*(..))" /> 
        <!--  将事务通知和切面组合   --> 
        <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods" /> 
    </aop:config>

DAO层开发

DAO层主要实现与数据库交互的代码:

UserInfoDAO接口

package com.digital.dao;

import java.util.List;
import com.digital.entity.*;

public interface UserInfoDAO {
    public List<UserInfo> search(UserInfo cond);

}

UserInfoDAOImpl

package com.digital.dao.impl;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;

import com.digital.dao.UserInfoDAO;
import com.digital.entity.UserInfo;

public class UserInfoDAOImpl implements UserInfoDAO {

    SessionFactory sessionFactory;
    //通过注入方式获得实例
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Override
    public List<UserInfo> search(UserInfo cond) {
        List<UserInfo> uiList = null;
        // 获得session
        Session session = sessionFactory.getCurrentSession();
        // 创建Criteria对象
        Criteria c = session.createCriteria(UserInfo.class);
        // 使用Example工具类创建示例对象
        Example example = Example.create(cond);
        // 为Criteria对象指定示例对象example作为查询条件
        c.add(example);
        // 执行查询
        uiList = c.list();
        // 返回结果
        return uiList;
    }
}

添加DAO的bean到applicationContext

<!-- 定义com.digital.dao.impl.UserInfoDAOImpl类-->
<bean id="userInfoDAO" class="com.digital.dao.impl.UserInfoDAOImpl">      
    <property name="sessionFactory" ref="sessionFactory" /></bean>

Service层开发

UserInfoService接口

package com.digital.service;

import java.util.List;
import com.digital.entity.*;

public interface UserInfoService {
    public List<UserInfo> login(UserInfo cond);
}

UserInfoServiceImpl

package com.digital.service.impl;

import java.util.List;

import com.digital.dao.UserInfoDAO;
import com.digital.entity.UserInfo;
import com.digital.service.UserInfoService;

public class UserInfoServiceImpl implements UserInfoService {

    UserInfoDAO userInfoDAO;    
    //注入获得实例
    public void setUserInfoDAO(UserInfoDAO userInfoDAO) {
        this.userInfoDAO = userInfoDAO;
    }

    @Override
    public List<UserInfo> login(UserInfo cond) {
        return userInfoDAO.search(cond);
    }

}

添加Service的bean到applicationContext

<!-- 定义UserInfoServiceImpl类,并为其userInfoDAO属性注入值-->
<bean id="userInfoService" class="com.digital.service.impl.UserInfoServiceImpl">      
    <property name="userInfoDAO" ref="userInfoDAO" />
</bean>

Action开发

package com.digital.action;

import java.util.List;

import com.digital.entity.*;
import com.digital.service.UserInfoService;
import com.opensymphony.xwork2.ActionSupport;

public class UserInfoAction extends ActionSupport {

    UserInfo ui;

    public UserInfo getUi() {
        return ui;
    }

    public void setUi(UserInfo ui) {
        this.ui = ui;
    }

    UserInfoService userInfoService;

    public void setUserInfoService(UserInfoService userInfoService) {
        this.userInfoService = userInfoService;
    }

    public String doLogin() throws Exception {
        List<UserInfo> uiList = userInfoService.login(ui);
        if (uiList.size() > 0) {
            // 登录成功,转发到到index.jsp
            return "index";
        } else {
            // 登录失败,重定向到login.jsp
            return "login";
        }

    }

}

Spring整合Struts2

先来回顾一下struts2执行原理:

S2SH整合开发——登录

此外,struts2还有个很重要的valuestack来保存action等东西:

S2SH整合开发——登录

创建action对象的方法有很多,一种是利用struts2本身的反射机制,通过ObjectFactory来创建action对象。第二个就是把创建对象委托给其他容器,例如spring。
Spring整合Struts2的目的在于使用Spring IOC容器来管理Struts2的Action。

web.xml配置

ssh框架中,我们通过配置就可以实现spring容器随着Tomcat/Jboss等的启动而自动启动,而无需我们手动开启。这是通过监听器来实现的,当spring容器启动后,自动读取并加载相应的配置文件。

<!-- 指定以Listerner方式启动Spring -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 指定Spring配置文件的位置 -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>
<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>

添加UserInfoAction的bean到applicationContext

用prototype,每个用户都会创建一个新的Bean实例。

<!-- 定义UserInfoAction类 ,并为其中属性userInfoService注入值 -->
<bean name="uiAction" class="com.digital.action.UserInfoAction" scope="prototype">
    <property name="userInfoService" ref="userInfoService" />
</bean>

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.i18n.encoding" value="utf-8"></constant>
    <!-- 定义一个名称为digital的包,继承struts 2的默认包,指定命名空间为"/" -->
    <package name="digital" namespace="/" extends="struts-default">
        <!-- 为类中的方法配置映射 -->
        <action name="doLogin" class="uiAction" method="doLogin"><!--class引用bean实例-->
            <result name="index" type="dispatcher">index.jsp</result>
            <result name="login" type="redirect">login.jsp</result>
        </action>
    </package>
</struts>    

关于dispatcher和redirect的区别

S2SH整合开发——登录

dispatcher用于两个组件协同工作的时候,而redirect用于一个工作完成之后开始下一个工作,重定向之后当前页面的所有数据信息在下一个页面将全部失效,也就是说,使用redirect跳转页面的时候不能把当前页面的参数传递到下一个页面。
比如:登录成功之后应该用redirect重定向不能用dispatcher,因为登录成功表示一个工作已经完成,如果用重定向的话,由于地址还是原来的地址,用户刷新页面之后又会要求重新登录,不符合常理。

创建交互页面

login.jsp

<%@ page language="java" import="java.util.*" pageEncoding="gbk"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>登录页</title>
</head>

<body>
    <s:form action="doLogin">
        <table>
            <tr>
                <s:textfield name="ui.userName" label="用户名" />
            </tr>
            <tr>
                <s:textfield name="ui.password" label="密码" />
            </tr>
            <tr>
                <s:submit value="登录" />
            </tr>
        </table>
    </s:form>

</body>
</html>

登录成功页面
index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<html>
  <head>    
    <title>系统首页面</title>
  </head>  
  <body>
      欢迎您,登录成功!
  </body>
</html>

Server MyEclipse Tomcat v8.5 was unable to start within 45 seconds. If the server requires more time…

解决办法是在Workpaces->.metadata->.plugins->org.eclipse.wst.server.core->servers.xml修改timeout大一点就行了,项目一大,所需的时间也就会越长。

执行流程

  1. 从页面开始,提交表单或者点击链接会触发一个action(doLogin)

  2. action交给struts2处理,读取src目录struts.xml文件,在配置中找到对应的action

  3. 根据class=”XXXAction”交给Spring(为什么struts的action会交给spring处理呢?
    原因是:Struts2提供一个jar包:struts2-spring-plugin-2.1.2.jar,有个struts.properties文件配置了这样一句话:struts.objectFactory.spring.autoWire = name。
    也就是有了上面那个jar包之后,根据name自动提交给Spring处理,读取Spring容器的配置文件/WebRoot/WEB-INF/applicationContext.xml文件。 根据applicationContext.xml配置文件找到xxx.xxx.action.xxxAction类,
    其中有一个属性xxxService,并提供了setxxxService()方法,由applicationContext.xml文件得知该xxxService对象由Spring容器依赖注入,set注入。

  4. 取得xxxService对象(接口对接口实现类的一个引用)后,调用它的方法。后面的就是访问DAO了,一长串省略号代替

  5. 执行的结果会在action的对应的方法中以字符串的形式给出。然后根据配置文件中的result.找到下一步要执行的动作,是跳转到页面显示还是继续交给其他的action处理。

相关标签: spring