概述
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
#properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/tedustore
username=root
password=
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.properties
static{
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对象,
//如果第一次调用,则返回null
Connection 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++) {
//获取当前参数的注解ann
Annotation[] 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();
}
@Override
public 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 = DemoController
Class 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;
//添加到map
urlMap.put(path, new UrlHandler(object,method));
}
}
}
//根据用户提交的URL路径获取(对象和方法)UrlHandler
public 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 Path
String 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);
}
}
最后
以上就是精明吐司为你收集整理的Spring框架的实现的全部内容,希望文章能够帮你解决Spring框架的实现所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复