昨天我学习了一个项目的登陆页面是如何校验的,例如用js或者jq。但是这方面的知识我真的实在是太薄弱了,实在不知道我可以总结出什么,所以昨天就没写博客总结。
今天老师则是讲了项目的登陆功能(看了项目觉得自己差的太多了,很多类和方法都闻所未闻),项目是挺古老的项目了,用的是struts和 ibatis框架。因为之前学过Mybatis,所以现在看一下Mytatis的前身ibatis还是可以看的懂一些的。由于项目比较大,所以每一个类的方法都比较多,看起来很乱,所以我就从新建了一个项目,只把登陆所需要的东西放到里面,这也是我今天要总结的:用struts和 ibatis框架实现登陆功能。
一.web.xml
不管你用什么框架,什么技术,每一个项目都会有一个web.xml文件 ,这是毋庸置疑的。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<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>
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
在这个文件中,我导入了必要的约束,配置了一个过滤器(struts框架提供给我们的)和其对应的过滤器映射。当我们发送请求时,过滤器会将我们的请求过滤掉(这里会过滤掉所有请求),然后分发给对应的Action来处理请求。这个过滤器还会自动去加载一个在src目录下的struts.xml的文件。
我还配置了项目的欢迎页面,用来在访问项目时,自动跳转的页面。
二.struts.xml文件
配置完了项目的web.xml,那么接下来就需要配置struts框架的核心配置文件了。
<?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>
<package name="custom-default" extends="struts-default">
<!-- 默认走的拦截器 -->
<action name="loginAction" class="com.java.action.LoginAction">
<result name="success"></result>
</action>
</package>
</struts>
在这里我也是简单的配置了一下(最简单的那种,只满足登陆功能的需求),我们导入相应的约束,并在struts标签中配置了一个action映射,用来处理用户登陆的请求。在这里我并没有声明执行哪一个拦截器栈,所以它会默认执行 默认的lan'拦截器栈。
三.Sql-Map-Config.xml
ibatis框架的核心配置文件的命名与其他框架有所不同,但是它的核心与Mybatis确是差不多的,只不过Mybatis使用sqlSession来操作数据库,而ibatis使用sqlMapClient(类似于Mybatis中的sqlSessionFactory)来操作数据库。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<!-- 该文件类似于Mybatis的核心配置文件 -->
<sqlMapConfig>
<!-- 从外部引入文件(去这个文件去寻找资源) -->
<properties resource="com/java/ibatis/database.properties" />
<!-- 配置事务管理器 -->
<transactionManager type="JDBC">
<!-- 配置数据源 -->
<dataSource type="SIMPLE">
<property name="JDBC.Driver" value="${driver}"></property>
<property name="JDBC.ConnectionURL" value="${url}" />
<property name="JDBC.Username" value="${username}" />
<property name="JDBC.Password" value="${password}" />
<property name="JDBC.DefaultAutoCommit" value="true" />
</dataSource>
</transactionManager>
<!-- 配置所要操作数据的sql语句 -->
<sqlMap resource="com/java/Mapper/t_limit_emp.xml"></sqlMap>
</sqlMapConfig>
这里要注意,Mybatis使用Mapper来“实现”接口,而在ibatis中却不这样做。但是我们依然要在ibatis核心配置文件中pe配置事务管理器,事务管理器(我们)所要操作的数据库(数据源)。这里我们会以引入文件的方式来引入查询所要返回的结果集,而不是定义一个Mapper映射来定义结果集。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap>
<resultMap class="com.java.bean.T_limit_Emp" id="T_limit_Emp">
<!-- 管理员表ID管理员表 -->
<result column="id" property="id" />
<!-- 帐号帐号 -->
<result column="userName" property="userName" />
<!-- 密码密码 -->
<result column="password" property="password" />
<!-- 中文姓名 -->
<result column="trueName" property="trueName" />
<!-- 操作时间默认getdate -->
<result column="operateTime" property="operateTime" />
<!-- 操作人最后操作了该数据的人 -->
<result column="operator" property="operator" />
<!-- 有效/无效有效状态-YesNo常用代码 -->
<result column="valid" property="valid" />
</resultMap>
<!-- 管理员登录 -->
<select id="adminLogin" parameterClass="com.java.bean.T_limit_Emp" resultMap="T_limit_Emp">
select * from t_limit_Emp where userName=#userName# and password=#password# and valid=1
</select>
<select id="selectAdressbyName" parameterClass="java.lang.String" resultClass="java.lang.String">
select d.url from T_limit_Emp
a,T_limit_EmpRole b ,T_limit_Right c ,T_limit_RightPage d ,T_limit_RoleRight e,T_limit_Role f
where a.id=b.empId and f.id=b.roleId and e.rightId=c.id and e.roleId=f.id and d.rightId=c.id and userName=#userName#
</select>
</sqlMap>
我们在sqlMap标签中,定义了resultMap结果集,给这个结果集声明了一个ID标识,用于在其他地方引用这个结果集。并且也想Mybatis一样,声明了映射类(用来指定返回的结果集是什么类型的),这一点好像和Hibernate有点相似。在声明完结果集,我们还要在当前文件中定义所要查询的sql语句,在标签中定义传入参数的类型和返回的结果集ID标识,这里还需要定义一个属于sql语句的ID标识,用来在需要的时候通过id来引用这个sql语句。
不仅如此,我们还在ibatis核心配置文件以<properties>标签引入了一个properties类型的文件,并在配置数据源的时候以${ key }的形势来获取文件中的value值。
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/officesystem?useUnicode=true&characterEncoding=UTF-8
username=root
password=root
四.Controller层
配置完我们登陆功能所需要的配置文件后,我们就可以开始着手写我们的controller了。在项目中,为了代码规范,现定义了一个baseAction ,在我们写action时候,只需要继承这个baseAction就可以了。
package com.java.action;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
//基本的action抽象类
//抽象类实现接口?为甚什么用泛型
public abstract class BaseAction<T> extends ActionSupport implements ModelDriven<T>{
//最基本的action抽象方法
public abstract String execute();
//模型驱动所需方法
}
这里有一个疑问,为什么在实现了ModelDriven<T>接口后,BaseAction也要定义泛型了呢?
下面我们来看一下LoginAction的代码:
package com.java.action;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.java.bean.T_limit_Emp;
import com.java.service.EmpInterface;
public class LoginAction extends BaseAction<T_limit_Emp> {
//创建一个对象,用于模型驱动
private T_limit_Emp t_limit_Emp=new T_limit_Emp();
@Override
public T_limit_Emp getModel() {
// TODO Auto-generated method stub
return t_limit_Emp;
}
@Override
public String execute() {
//创建一个service层对象
EmpInterface empInterface = new EmpInterface();
//得到查询的结果
T_limit_Emp emp = empInterface.adminLogin(t_limit_Emp);
System.out.println(emp);
//当用户存在时
if(empInterface!=null) {
List<String> list = empInterface.selectAdressbyName(emp.getUserName());
//将list集合放入set集合
Set<String> set=new HashSet<String>(list);
set.add("frame/main.jsp");
set.add("frame/top.jsp");
set.add("frame/menu.jsp");
//将set集合封装到实体类的属性
emp.setPageSet(set);
}
return null;
}
}
在这个类中,我们首先创建了一个对象,这个对象就是我们模型驱动所要使用的对象。然后我们在execute()方法里些一些业务。如果 模型驱动中的模型中,没有前台页面传递过来的name属性值的属性,那么这个name属性值所对应的value在后台就会接收不到,但是并不会报出异常。
比如,我们new了一个service层的对象,并用这个对象调用了adminLogin()方法,方法所需要的参数的就是模型所封装的对象。用这个对象来进行查询,返回一个emp对象。
接下来就是根据这个emp进行一些其他的操作了,这里我就不在多说。
五.service层
package com.java.service;
import java.util.List;
import com.java.bean.T_limit_Emp;
import com.java.dao.T_limit_EmpDao;
import com.java.dao.T_limit_EmpRoleDao;
public class EmpInterface {
//封装两个dao层的对象
private T_limit_EmpDao t_limit_EmpDao = new T_limit_EmpDao();
private T_limit_EmpRoleDao t_limit_EmpRoleDao = new T_limit_EmpRoleDao();
//用dao层对象来调用方法
public T_limit_Emp adminLogin(T_limit_Emp emp){
T_limit_Emp t_limit_Emp_return=t_limit_EmpDao.adminLogin(emp);
return t_limit_Emp_return;
}
public List<String> selectAdressbyName(String userName) {
List<String> list =t_limit_EmpDao.selectAdressbyName(userName);
return list;
}
}
在service层中,自然而然的肯定会封装dao层的对象,这里我们封装了两个dao层的对象。然后通过dao层的对象继续调用方法,返回值仍然是一个emp对象。
六.dao层
在我的印象中,dao层就是用来写查询数据库的sql语句的。这里也不例外,但是这里 “写” 的方式确实有点与众不同。
package com.java.dao;
import java.util.List;
import com.java.bean.T_limit_Emp;
import com.java.ibatis.SqlMapConn;
public class T_limit_EmpDao {
//封装一个用于操作数据库的对象
private SqlMapConn sqlMapConn=new SqlMapConn();
public T_limit_Emp adminLogin(T_limit_Emp emp) {
return (T_limit_Emp)sqlMapConn.getObject("adminLogin", emp);
}
public List selectAdressbyName(String username) {
List<String> list=sqlMapConn.select("selectAdressbyName", username);
return list;
}
}
这里首先创建了一个操作数据库的类qlMapConn,然后通过这个类的对象方法来操作数据库。sqlMapConn对象调用的方法和之前的有所不同,这里的方法不仅要传递查询时所需要的参数,还需要添加一个 “引用” ,这个引用用来指用查询数据库的sql语句。
查询数据库的sql语句定义在了SqlMapConn对象当中,我们来看一下SqlMapConn类:
package com.java.ibatis;
import java.io.IOException;
import java.io.Reader;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
import com.java.bean.T_limit_Emp;
//该类中封装了用于操作数据库的对象,和操作数据库的方法
public class SqlMapConn {
//声明一个操作数据库的对象,为什么人家可以变为finall类型?
private static SqlMapClient sqlMapClient;
//用静态代码块给属性赋值,静态代码块中属性只能是静态的。
static {
//声明ibatis的核心配置文件所在路径
String url="com/java/ibatis/Sql-Map-Config.xml";
try {
//将资源变成输入流
Reader reader=Resources.getResourceAsReader(url);
//用流创建一个操作数据库的对象
sqlMapClient=SqlMapClientBuilder.buildSqlMapClient(reader);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//定义一个通用的查询数据的方法
public List select(String reflexion,Object obj) {
List<String> list=null;
try {
list=sqlMapClient.queryForList(reflexion, obj);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
}
//查询一个数据的方法
public Object getObject(String reflexion,Object obj) {
Object obj_return=null;
try {
obj_return=(T_limit_Emp)sqlMapClient.queryForObject(reflexion, obj);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj_return;
}
}
在这个类中,定义了操作数据库的方法和操作数据库的sql语句,可以说,这个类就是操作数据库的最 “底层” 的类,而sqlMapClient则是操作数据库的对象。
这里的sql语句存放在ibatis的核心配置文件中。
七.总结
总的来说,其实并不需要惧怕登陆的代码,只不过是controller层接收参数,通过service层业务处理,在通过dao层来查询数据库,将查询到的结果返回controller层处理。就是MVC模式的3层逐层调用,只不过不同框架的语法不同,例如Mybatis和ibatis的语法结构就不太一样。