Spring框架的实现

来源:互联网 发布:哪个软件可以看陆小凤 编辑:程序博客网 时间:2024/06/10 12:26
MVC(Model + View + Controller)
M-Model模型:职责是负责业务逻辑。包含两层:业务数据和业务处理逻辑。比如实体类、DAO、Service都属于模型层
V-View视图:职责是负责显示界面和用户交互(收集用户信息)属于视图的组件是不包含业务逻辑和控制逻辑的JSP。
C-Controller控制器:控制器是模型层M和视图层V之间的桥梁,用于控制流程,比如:在Servlet项目中的单一控制器ActionServlet
此案例演示了Spring框架里的getBean两种重载的方法

原型开发与测试:

访问login.do


1.编写配置文件 conf/context.xml

<?xml version="1.0" encoding="UTF-8"?> <beans>     <!-- 声明控制器组件 -->     <bean class="cn.tedu.tstore.controller.LoginController"/> </beans>

编写文件conf.properties

#propertiesdriver=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/tedustoreusername=rootpassword=MaxActive=5

2.web.xml配置文件

<servlet>    <servlet-name>DispatcherServlet</servlet-name>    <servlet-class>cn.tedu.base.web.DispatcherServlet</servlet-class>    <init-param>        <param-name>config</param-name>        <param-value>conf/context.xml</param-value>    </init-param>    <load-on-startup>1</load-on-startup></servlet><servlet-mapping>    <servlet-name>DispatcherServlet</servlet-name>    <url-pattern>*.do</url-pattern></servlet-mapping>
3.数据库连接类:
package cn.tedu.tstore.util;import java.io.IOException;import java.io.InputStream;import java.sql.Connection;import java.sql.SQLException;import java.util.Properties;import org.apache.commons.dbcp.BasicDataSource;public class DBUtil {//引用ThreadLocal用于将连接对象绑定到当前线程private static ThreadLocal<Connection> c = new ThreadLocal<Connection>();private static BasicDataSource dataSource;private static String driver;private static String url;private static String username;private static String password;//读取配置文件,获取4个连接参数 conf.propertiesstatic{try {//读取resource中的配置文件String file="conf.properties";InputStream in = DBUtil.class.getClassLoader().getResourceAsStream(file);Properties config=new Properties();config.load(in);driver=config.getProperty("driver");url=config.getProperty("url");username=config.getProperty("username");password=config.getProperty("password");//打桩!!!int max=Integer.parseInt(config.getProperty("MaxActive"));dataSource = new BasicDataSource();dataSource.setDriverClassName(driver);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);} catch (IOException e) {e.printStackTrace();throw new RuntimeException(e);}}public static Connection getConnection()throws SQLException {try {//从当前线程中获取当前的conn对象,//如果第一次调用,则返回nullConnection conn = c.get();//第一次没有连接时候,立即创建连接if(conn==null) {conn=dataSource.getConnection();//将连接对象保存到当前线程中c.set(conn);}return conn;} catch (Exception e) {e.printStackTrace();throw new SQLException(e);}}public static void begin() {Connection conn = c.get();if(conn!=null){try {conn.setAutoCommit(false);} catch (SQLException e) {e.printStackTrace();}}}public static void commit(){//从当前线程中获取连接对象,并且提交事务Connection conn = c.get();if(conn!=null){try {conn.commit();} catch (SQLException e) {e.printStackTrace();}}}public static void rollback(){Connection conn = c.get();if(conn!=null){try {conn.rollback();} catch (SQLException e) {e.printStackTrace();}}}public static void close(){Connection conn = c.get();if(conn!=null){try {conn.close();//在连接关闭以后,将连接对象从当前线程中删除c.remove();} catch (SQLException e) {e.printStackTrace();}}}}

4.用户类:

package cn.tedu.tstore.entity;import java.io.Serializable;import java.util.Date;public class User implements Serializable {private Integer id;private String username;private String password;private String email;private String mobile;private Date createTime;public User() {}public User(Integer id, String username, String password, String email, String mobile, Date createTime) {super();this.id = id;this.username = username;this.password = password;this.email = email;this.mobile = mobile;this.createTime = createTime;}public Integer getId() {return id;}public void setId(Integer 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 String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public String getMobile() {return mobile;}public void setMobile(String mobile) {this.mobile = mobile;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;}public boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;User other = (User) obj;if (id == null) {if (other.id != null)return false;} else if (!id.equals(other.id))return false;return true;}public String toString() {return "User [id=" + id + ", username=" + username + ", password=" + password + ", email=" + email + ", mobile=" + mobile + ", createTime=" + createTime + "]";}}

5.DAO类:

package cn.tedu.tstore.dao;import cn.tedu.tstore.entity.User;public interface UserDao {User findByName(String username) throws SQLException;}package cn.tedu.tstore.dao;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import cn.tedu.tstore.entity.User;import cn.tedu.tstore.util.DBUtil;public class UserDaoImpl implements UserDao{private User mapRow(ResultSet rs) throws SQLException {User user=new User();user.setId(rs.getInt("id"));user.setUsername(rs.getString("username"));user.setPassword(rs.getString("password"));user.setEmail(rs.getString("email"));user.setMobile(rs.getString("mobile"));user.setCreateTime(rs.getTimestamp("create_time"));return user;}public User findByName(String username) throws SQLException {Connection conn = DBUtil.getConnection();String sql = "select id,username,password,email,mobile,create_time from user where username=?";PreparedStatement ps = conn.prepareStatement(sql);ps.setString(1, username);ResultSet rs = ps.executeQuery();while (rs.next()) {User user = mapRow(rs);return user;}return null;}}

package cn.tedu.tstore.dao;import java.lang.reflect.InvocationHandler;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import cn.tedu.tstore.util.DBUtil;public class ConnectionHandler implements InvocationHandler{private UserDao dao;public ConnectionHandler(UserDao dao) {this.dao=dao;}public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{try {//打开连接DBUtil.getConnection();DBUtil.begin();//利用反射API执行dao的方法Object val = method.invoke(dao, args);DBUtil.commit();return val;}catch (InvocationTargetException e) {//发生InvocationTargetException时候,是//dao中被调用的方法出现了异常如 SQLException//找到实际dao的方法抛出的异常Throwable ex = e.getTargetException();DBUtil.rollback();throw ex;}catch(Exception e){e.printStackTrace();}finally {DBUtil.close();}return null;}}
6.开发注解:
package cn.tedu.base.web;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;@Retention(RetentionPolicy.RUNTIME)public @interface RequestMapping {String value();}

package cn.tedu.base.web;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;//注解将保留到程序运行期间@Retention(RetentionPolicy.RUNTIME)//注解只能在方法参数上使用@Target(ElementType.PARAMETER)public @interface Param {String value();}

7.Map表类:

package cn.tedu.base.web;import java.util.HashMap;/** * 用于从控制器带回需要到JSP中显示的数据 * 增加这个类名的目的就是为了使用反射API时候检查 * 方法参数的类型 */public class ModelMap<K,V> extends HashMap<K,V>{private static final long serialVersionUID = 1L;}

package cn.tedu.base.web;import java.util.HashMap;public class SessionMap<K, V> extends HashMap<K, V> {private static final long serialVersionUID = 1L;}

8.JSP文件:

WEB-INF下建文件夹jsp里面有login.jsp和ok.jsp,其中login.jsp在webapp也有一份

ok.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title></head><body><h1>OK</h1></body></html>

login.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><c:set var="base" scope="request" value="${pageContext.request.contextPath}"></c:set><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>欢迎登录</title></head><body><form action="${base}/login.do" method="post">      <div>        <input type="text" placeholder="User Name" name="username" value="${username}">${error}      </div>      <div>        <input type="password" placeholder="Password" name="password">      </div>      <div class="row">        <div>          <button type="submit">登录</button>        </div>      </div>    </form></body></html>

9.开发控制器类

package cn.tedu.tstore.controller;import java.sql.SQLException;import org.omg.CORBA.CTX_RESTRICT_SCOPE;import cn.tedu.base.web.ApplicationContext;import cn.tedu.base.web.ModelMap;import cn.tedu.base.web.Param;import cn.tedu.base.web.RequestMapping;import cn.tedu.base.web.SessionMap;import cn.tedu.tstore.dao.UserDao;import cn.tedu.tstore.dao.UserDaoImpl;import cn.tedu.tstore.entity.User;public class LoginController {@RequestMapping("/login.do")public String login(@Param("username") String username,@Param("password") String password,ModelMap<String,Object> map,SessionMap<String, Object> session,ApplicationContext ctx) throws SQLException {//UserDao userDao = new UserDaoImpl();UserDao userDao = ctx.getBean("userDaoImpl",UserDao.class);User user = userDao.findByName(username);if(user==null) {map.put("error", "没有注册");return "login";// /WEB-INF/jsp/login.jsp}if(user.getPassword().equals(password)) {map.put("msg", "欢迎回来: "+user.getUsername());session.put("user", user);//return "msg";return "ok";}map.put("error", "密码错误");return "login";}}

10.对象方法设置获取类:

package cn.tedu.base.web;import java.lang.annotation.Annotation;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.Map;public class UrlHandler {private Object obj;private Method method;public UrlHandler() {}public UrlHandler(Object obj, Method method) {super();this.obj = obj;this.method = method;}public Object getObj() {return obj;}public void setObj(Object obj) {this.obj = obj;}public Method getMethod() {return method;}public void setMethod(Method method) {this.method = method;}/** * UrlHandler 中添加执行控制器方法的方法 * 在当前控制器对象obj的当前方法method * 参数map用于封装返回到request中的数据 * @throws InvocationTargetException  * @throws IllegalArgumentException  * @throws IllegalAccessException  */public String execute(Map<String,String[]> paramMap,ModelMap<String,Object> map,SessionMap<String, Object> session,ApplicationContext ctx) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {//检查当前方法使用包含ModelMap类型的参数//如果包含ModelMap就传递参数调用方法//如果不包含参数就不传递参数调用方法//String String[] String String[]//paramMap = {"user"->{"Tom"},"age"->{"10"}}//检查当前方法method的参数(Parameter)类型Class[] patamTypes = method.getParameterTypes();//如果参数长度为0,则说明method方法没有参数if(patamTypes.length==0) {Object val = method.invoke(obj);return val.toString();}//有参数的情况,检查参数的类型,根据参数的类型//顺序创建目标参数数组Object[] param = new Object[patamTypes.length];//检测每个参数上的注解Annotation[][] anns = method.getParameterAnnotations();//根据参数类型来拼凑参数//param    = {1,0.5,map}//patamTypes = {int.class,double.class,ModelMap.class}for(int i=0; i<patamTypes.length;i++) {//获取当前参数的注解annAnnotation[] ann = anns[i];//获取Patam 注解Param p = null;//没有注解if(ann.length==1) {p = (Param)ann[0];//有Param 注解}if(p!=null){ String key=p.value(); //key 为 user 或 age  //根据key获取表单中的参数值 String[] paramValues= paramMap.get(key); if(paramValues==null){ continue; } //paramValues的参数情况参考如下: //paramValues={"Tom"} //paramValues={"10"} //需要根据目标参数的类型,进行类型转换 Class type=patamTypes[i]; if(type == String.class){ //如果是字符串类型,就不需要转换类型了 param[i]=paramValues[0]; }else if(type == int.class ||  type==Integer.class){ //将paramValues中的数据转换为 整数 //填加到目标参数的数组中 param[i]=Integer.parseInt( paramValues[0]); }else if(type==double.class|| type==Double.class){ param[i]=Double.parseDouble( paramValues[0]); }else if(type==float.class|| type==Float.class){ param[i]=Float.parseFloat( paramValues[0]); }else if(type==long.class|| type==Long.class){ param[i]=Long.parseLong( paramValues[0]); }else if(type==String[].class){ //处理字符串数组情况 param[i]=paramValues; } }else{//p == null的情况下要处理ModelMap //type是按照“顺序”出现的,目标中参数的类型 Class type=patamTypes[i]; if(type==ModelMap.class){ //如果参数类型是ModelMap则传递参数map param[i]=map; }else if(type==SessionMap.class){ //注入Session集合 param[i]=session; }else if(type==ApplicationContext.class){ param[i]=ctx; } }}Object val = method.invoke(obj,param);return val.toString();}@Overridepublic String toString() {return "UrlHandler [obj=" + obj + ", method=" + method + "]";}}

11.解析context.xml文件类:

package cn.tedu.base.web;import java.io.InputStream;import java.util.Collection;import java.util.HashMap;import java.util.List;import java.util.Map;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;/** * Application 应用 * Context 上下文,管家 * @author soft01 * */public class ApplicationContext {private Map<String, Object> beans=new HashMap<String, Object>();public ApplicationContext() {}/** * 根据配置文件初始化全部对象 * @param cfg xml配置文件 */public ApplicationContext(String cfg) {init(cfg);}public void init(String cfg) {try {InputStream in = getClass().getClassLoader().getResourceAsStream(cfg);SAXReader reader = new SAXReader();Document doc = reader.read(in);Element root = doc.getRootElement();List<Element> list = root.elements("bean");for(Element e : list) {String className = e.attributeValue("class");Class cls = Class.forName(className);Object obj = cls.newInstance();String name = cls.getName();//name = "cn.tedu.DemoBean"name = name.substring(name.lastIndexOf(".")+1);String key = name.substring(0,1).toLowerCase()+name.substring(1);//key = "demoBean"System.out.println(key);beans.put(key, obj);}} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}}public Collection<Object> getBeans(){//Map 类型上有一个方法values() 用于返回//Map 中全部的value对象return beans.values();}public <T> T getBean(String name, Class<T> cls){return (T)beans.get(name);}public String toString() {return "ApplicationContext [beans=" + beans + "]";}}

12.找注解方法类:

package cn.tedu.base.web;import java.lang.reflect.Method;import java.util.Collection;import java.util.HashMap;import java.util.Map;/** * 根据用户请求的路径,获取对应的控制器对象和方法 * 并且执行这个方法 * @author soft01 * */public class HandlerMapping {//map 中的key是用户请求的url,map中的value是//对象和控制方法组成的一个实例private Map<String,UrlHandler> urlMap = new HashMap<String,UrlHandler>();//init方法用于根据控制器对象初始化map集合public void init(Collection<Object> controllers) {for(Object object : controllers) {//object = DemoController//利用反射API获取类上注解// cls = DemoControllerClass cls = object.getClass();//获取类上标注的注解RequestMapping rm = (RequestMapping)cls.getAnnotation(RequestMapping.class);String path1 = "";//获取注解上标注的值if(rm!=null) {path1 = rm.value();}System.out.println(path1);//解析方法上的注解//找到全部方法信息Method[] methods = cls.getDeclaredMethods();for(Method method : methods) {//找到方法上声明的注解RequestMapping rm2 = method.getAnnotation(RequestMapping.class);System.out.println("rm2");//如果没有找到注解的方法就跳过这个方法if(rm2==null) {continue;}String sub = rm2.value();System.out.println(sub);String path = path1+sub;//添加到mapurlMap.put(path, new UrlHandler(object,method));}}}//根据用户提交的URL路径获取(对象和方法)UrlHandlerpublic UrlHandler getUrlHandler(String path) {return urlMap.get(path);}public String toString() {return "HandlerMapping [urlMap=" + urlMap + "]";}}

13.编写Servlet

package cn.tedu.base.web;import java.io.IOException;import java.lang.reflect.Method;import java.util.Enumeration;import java.util.Map;import javax.servlet.RequestDispatcher;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;/** * Servlet implementation class DispatcherServlet */public class DispatcherServlet extends HttpServlet {private static final long serialVersionUID = 1L;private ApplicationContext applicationContext;private HandlerMapping handlerMapping;/** * Servlet初始化方法,加载控制器类 */public void init() throws ServletException {//读取context.xml//解析出类名String filename = getServletConfig().getInitParameter("config");applicationContext = new ApplicationContext(filename);System.out.println(applicationContext);handlerMapping = new HandlerMapping();//getBeans 方法获取 applicationContext 中//创建的全部控制器对象handlerMapping.init(applicationContext.getBeans());}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request,response);}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("Hello World!");try {//获得用户请求时候的URL路径String url = request.getRequestURI();//删除url中开头的Context PathString contextPath = request.getContextPath();if(url.startsWith(contextPath)) {url=url.substring(contextPath.length());}                                                                                                                  //查找需要执行的对象和方法UrlHandler handler = handlerMapping.getUrlHandler(url);Map<String,String[]> paramMap = request.getParameterMap();//传递Session参数SessionMap<String, Object> sessionMap= new SessionMap<String, Object>();HttpSession session=request.getSession();Enumeration<String> en=session.getAttributeNames();while(en.hasMoreElements()){String name=en.nextElement();sessionMap.put(name, session.getAttribute(name));}//利用UrlHandler执行控制器方法ModelMap<String,Object> map = new ModelMap<String,Object>();//将全部表单参数paramMap传递给控制器方法String target = handler.execute(paramMap,map,sessionMap,applicationContext);//将map中需要传递到JSP中的数据,复制到//request的attribute中for(String key : map.keySet()) {Object val = map.get(key);request.setAttribute(key, val);}//赋值Session参数for(String key: sessionMap.keySet()){Object val=sessionMap.get(key);session.setAttribute(key, val); }//利用反射执行执行控制器对象的方法//Object obj = handler.getObj();//Method method = handler.getMethod();////执行目标方法//Object val = method.invoke(obj);//String target = val.toString();processView(request,response,target);} catch (Exception e) {e.printStackTrace();throw new ServletException(e);} //response.setContentType("text/html");//response.getWriter().print("OK"); }/** * 处理视图(显示)结果,根据target * 来决定如何处理 * 1. 如果以redirect 为开头就进行重定向处理 * 如果是http开始就绝对路径重定向 * 如果不是http开始的就补上 contextPath再重定向 * 2. 如果不是以 redirect 就直转发 * @param request * @param response * @param target */private void processView(HttpServletRequest request,HttpServletResponse response,String target) throws ServletException,IOException{if(target==null) {throw new ServletException("没有结果");}if(target.startsWith("redirect:")) {//重定向String path = target.substring("redirect:".length());if(!path.startsWith("http")) {path = request.getContextPath()+path;}response.sendRedirect(path);}else {//转发String path = "/WEB-INF/jsp/"+target+".jsp";forward(request,response,path);}}private void forward(HttpServletRequest request, HttpServletResponse response, String path) throws ServletException, IOException {RequestDispatcher rd = request.getRequestDispatcher(path);rd.forward(request, response);}}

原创粉丝点击