基于配置文件的控制器
在上节所做的简单控制器的基础上,将其做成基于配置文件的控制器,通过读取解析xml文件中的标签配置,分发请求给特定的action处理类进行处理。
SimpleController工程
SimpleController工程目录:
工程新创建了工具类MyTools.java,重写了SimpleController.java
MyTools.java
MyTools中定义了readXml方法,代码没有用现有的几种解析xml文件的方式,而是自己实现了简单的读取和解析,参数为actionName和xml配置文件的路径,返回解析的相应action标签内容的Map数组。这种方式比较傻,后来知道有专门解析xml文件的方法后又重写了代码。
package sc.ustc.tool;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class MyTools {
public Map<String, String> readXml(String actionName, String path) throws FileNotFoundException {
File fd = new File(path);
BufferedReader br = new BufferedReader(new FileReader(fd));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = br.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
String[] sl = sb.toString().split("</action>");
Map<String, String> map = new HashMap<String, String>();
for (int i = 0; i < sl.length; i++) {
String acName = sl[i].substring(sl[i].indexOf("name=\"") + 6);
if (acName.startsWith(actionName + "\"")) {
map.put("action", actionName);
String classN = acName.substring(acName.indexOf("class=\"") + 7);
map.put("class", classN.substring(0, classN.indexOf("\"")));
String methodN = classN.substring(classN.indexOf("method=\"") + 8);
map.put("method", methodN.substring(0, methodN.indexOf("\"")));
String[] result = methodN.split("<result");
for (int j = 1; j < result.length; j++) {
String resN = result[j].substring(result[j].indexOf("name=\"") + 6);
String resT = resN.substring(resN.indexOf("type=\"") + 6);
String resV = resT.substring(resT.indexOf("value=\"") + 7);
String res = resT.substring(0, resT.indexOf("\"")) + "-" + resV.substring(0, resV.indexOf("\""));
map.put("result" + resN.substring(0, resN.indexOf("\"")), res);
}
}
}
return map;
}
}
SimpleController.java
SimpleController类拦截.sc请求,调用readXml获得相应的action标签项,通过java反射机制,调用相应class的method,根据返回值再做相应的分发。
package sc.ustc.controller;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import sc.ustc.tool.MyTools;
public class SimpleController extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html,charset=utf-8");
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
String actionName = request.getServletPath().toString();
String[] actionUrl = actionName.split("/");
actionName = actionUrl[actionUrl.length - 1];
String path = this.getServletContext().getRealPath("WEB-INF/classes/controller.xml");
MyTools mt = new MyTools();
Map<String, String> actionMap = mt.readXml(actionName.substring(0, actionName.indexOf(".")), path);
if (!actionMap.isEmpty()) {
String classN = actionMap.get("class");
String methodN = actionMap.get("method");
try {
Class cl = Class.forName(classN);
Method m = cl.getDeclaredMethod(methodN, HttpServletRequest.class, HttpServletResponse.class);
String result = (String) m.invoke(cl.newInstance(), request, response);
String resN = actionMap.get("result" + result);
String resT = resN.substring(0, resN.indexOf("-"));
String resV = resN.substring(resN.indexOf("-") + 1);
if (resT.equals("foward")) {
request.getRequestDispatcher(resV).forward(request, response);
} else if (resT.equals("redirect")) {
response.sendRedirect(resV);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
} else {
response.sendRedirect("/UseSC/jsp/Login.jsp");
}
}
}
UseSC工程
简单的web工程,用来测试上面写的框架
UseSC工程:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>sc</servlet-name>
<servlet-class>sc.ustc.controller.SimpleController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>sc</servlet-name>
<url-pattern>*.sc</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>/Login.jsp</welcome-file>
</welcome-file-list>
</web-app>
controller.xml
与Struts2框架类似,此即为框架要解析的配置文件,通过解析此文件来做拦截,转发等操作
<?xml version="1.0" encoding="UTF-8"?>
<sc-configuration>
<controller>
<action name="login" class="water.ustc.action.LoginAction"
method="handleLogin">
<result name="success" type="foward" value="Welcome.jsp"></result>
<result name="failure" type="redirect" value="Login.jsp"></result>
</action>
<action name="regist" class="water.ustc.action.RegisterAction"
method="handleRegist">
<result name="success" type="foward" value="Welcome.jsp"></result>
<result name="failure" type="redirect" value="Regist.jsp"></result>
</action>
</controller>
</sc-configuration>
测试
用户输入用户名密码,点击登录后,action提交表单至simpleController控制器处理,simpleController解析action后将调用LoginAction,LoginAction查询数据库,进行验证,并根据验证结果返回success或者failure,simpleController根据返回结果再进行页面转发或重定向。
UseSC工程其他代码
简单的登录注册界面以及登录注册的代码,用于测试框架
Login.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>please login!</title>
</head>
<body>
<div>
<h3>请登录:</h3><br>
<form action="login.sc" name="loginForm">
<div>账  号:<input type="text" name="id" /></div>
<div>密  码:<input type="password" name="password" /></div>
<div><input type="submit" name="login" value="登录" /></div>
</form>
<div>
<font color="red">${sessionScope.loginMessage }</font>
</div>
<br>
<div>
如果您还不是我们的用户,请<a href="/UseSC/Regist.jsp">点击注册</a>
</div>
<%
session.removeAttribute("loginMessage");
%>
</div>
</body>
</html>
Welcome.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<body>
<div>
尊敬的${sessionScope.id },您好!
</div>
<div>
<a href="/UseSC/Login.jsp">退出账户</a>
</div>
</body>
</html>
LoginAction.java
package water.ustc.action;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import water.ustc.dao.LoginDao;
import water.ustc.tools.Tools;
public class LoginAction extends HttpServlet {
private static final long serialVersionUID = 1L;
public String handleLogin(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String id = Tools.setUtf(request.getParameter("id"));
String password = request.getParameter("password");
LoginDao userDao = new LoginDao();
HttpSession session = request.getSession();
if (userDao.select(id, password) != null && !userDao.select(id, password).isEmpty()) {
session.setAttribute("id", id);
return "success";
} else {
session.setAttribute("loginMessage", "用户名或密码错误!");
return "failure";
}
}
}
Regist.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<body>
<form action="regist.sc" name="loginForm" accept-charset="utf-8">
<div>账  号:<input type="text" name="id" /></div>
<div>密  码:<input type="text" name="password" /></div>
<div><input type="submit" name="regist" value="注册" /></div>
</form>
<div>
<font color="red">${sessionScope.registMessage }</font>
</div>
<%
session.removeAttribute("registMessage");
%>
</body>
</html>
RegistAction.java
package water.ustc.action;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import water.ustc.dao.LoginDao;
import water.ustc.tools.Tools;
public class RegisterAction extends HttpServlet {
private static final long serialVersionUID = 1L;
public String handleRegist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String id = Tools.setUtf(request.getParameter("id"));
String password = request.getParameter("password");
LoginDao userDao = new LoginDao();
HttpSession session = request.getSession();
if (userDao.select(id, password) != null && !userDao.select(id, password).isEmpty()) {
session.setAttribute("registMessage", "用户名已存在!");
return "failure";
} else {
userDao.insert(id, password);
session.setAttribute("id", id);
return "success";
}
}
}
LoginDao.java
package water.ustc.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
public class LoginDao {
String driver = "com.mysql.jdbc.Driver";
String dbName = "user";
String passWord = "";
String userName = "root";
String url = "jdbc:mysql://localhost:3306/" + dbName;
public List<List<String>> select(String id, String password) {
String sql = "select * from useraccount where name = ? and password = ?";
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
List<List<String>> listlist = new ArrayList();
List<String> list = new ArrayList();
try {
// 加载驱动
Class.forName(driver);
// 获得连接
conn = DriverManager.getConnection(url, userName, passWord);
// 创建prepareStatement
ps = conn.prepareStatement(sql);
ps.setString(1, id);
ps.setString(2, password);
// 执行操作
rs = ps.executeQuery();
while (rs.next()) {
list.add(rs.getString(1));
list.add(rs.getString(2));
listlist.add(list);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null) {
rs.close();
}
if (ps != null) {
ps.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return listlist;
}
public void insert(String id, String password) {
String sql = "insert into useraccount(name,password) values(?,?)";
Connection conn = null;
PreparedStatement ps = null;
try {
// 加载驱动
Class.forName(driver);
// 获得连接
conn = DriverManager.getConnection(url, userName, passWord);
// 创建prepareStatement
ps = conn.prepareStatement(sql);
ps.setString(1, id);
ps.setString(2, password);
// 执行操作
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (ps != null) {
ps.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
对Struts2控制器的理解
Struts2框架是MVC框架,Struts2控制器根据用户的请求决定调用哪个Action组件进行处理,决定执行后返回到哪个视图,将业务逻辑抽离出来,使得程序员仅仅需要关心业务逻辑的实现而无需处理视图的跳转,业务模型中也只有业务处理的代码,结构清晰。
基于配置的控制器和注解的控制器各自优缺点。
基于配置:
优点:集中式管理,与代码没有绑定,进一步降低了耦合,怎强可拓展性,使代码维护更加方便。
缺点:需要使用解析工具,开发时较麻烦,coding时无法验证准确性。
基于注解:
优点:提高开发效率,不需要使用解析工具,coding时可验证准确性。
缺点:与代码耦合高,项目庞大时代码维护,修改不方便。