采用的MVC三层架构
知识点:
1. 框架(中央控制器)
作用:
注解:利用注解将每个Action类加上标注,访问时通过客户端发送的访问地址来判断要执行哪个Action 。这里需要用到控制器(一个Servlet,中央控制器),在web.xml文件中配置这个Servlet的范围,在客户端发送的地址中带.do的都栏截。
这个Servlet在应用启动时就启动,在init(servlet启动时)方法中 遍历应用下所有的带有指定注解的类。将类实例化后放入MAP中,MAP中的key为地址标注(在客户端发送的请求地址中获得),value就是对应的类。下次截获客户请求地址时,截取地址匹配这个MAP中的key 。 如果能找到,利用反射的方试执行指定的方法。方法的名称也是从客户端请求URL中请求参数中获得。
注意:当我们加载类时,需要加载类中父类和使用到的其它的类。定义一个类继承于ClassLoader, 将加载器转入,指定父加载器。然后写一个方法,方法内读取类文件成字节码,给内存。然后用ClassLoader的defineClass方法将内存的字节码转成一个Class对象
package com.itheima.framework;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.itheima.bean.privilege.Employee;
import com.itheima.service.privilege.SecurityService;
import com.itheima.utils.ClassFactory;
import com.itheima.utils.WebUtils;
public class ControllerServlet extends HttpServlet {
// 定义一个map,用于存放action与路径
public static Map<String, Object> map = new HashMap<String, Object>();
@Override
public void init() throws ServletException {
// 获取classes目录
String classpath = this.getServletContext().getRealPath(
"/WEB-INF/classes");
File file = new File(classpath);
scan(file);
}
private void scan(File file) {
if (file.isFile()) {
if (file.getName().endsWith("class")) {
final String filepath = file.getPath();
MyLoader myLoader = new MyLoader(
ControllerServlet.class.getClassLoader());
Class clazz = myLoader.myDefineClass(filepath);
Control contrl = (Control) clazz.getAnnotation(Control.class);
if (contrl != null) {
Object action;
try {
action = clazz.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
String uri = contrl.value();
map.put(uri, action);
}
}
} else {
File[] files = file.listFiles();
for (File f : files) {
scan(f);
}
}
}
class MyLoader extends ClassLoader {
public MyLoader(ClassLoader parent) {
super(parent);
}
public Class myDefineClass(String filepath) {
try {
InputStream in = new FileInputStream(filepath);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
while ((len = in.read(buffer)) != -1) {
bout.write(buffer, 0, len);
}
byte[] boutArr = bout.toByteArray();
Class clazz = super.defineClass(null, boutArr, 0,
boutArr.length);
return clazz;
} catch (FileNotFoundException e) {
throw new RuntimeException("没有找到相对应的类文件");
} catch (IOException e) {
throw new RuntimeException("读取类文件时发生错误");
}
}
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String uri = request.getRequestURI();
uri = uri
.substring(request.getContextPath().length(), uri.length() - 3);
Object action = map.get(uri);
String methodType = request.getParameter("method");
Method method;
try {
method = action.getClass().getMethod(methodType,
HttpServletRequest.class, HttpServletResponse.class);
} catch (Exception e) {
throw new RuntimeException("没有找到与之对应的方法");
}
try {
Permission permission = method.getAnnotation(Permission.class);
if (permission==null || checkPrivilege(permission, request)) {
method.invoke(action, request, response);
} else {
request.setAttribute("message", "你没有权限访问该页面,请联系管理员");
request.setAttribute("returnURL", request.getContextPath()
+ "/control/common/message.do?method=main");
WebUtils.forward("/WEB-INF/pages/common/message.jsp", request,
response);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private boolean checkPrivilege(Permission permission,
HttpServletRequest request) {
SecurityService securityService = ClassFactory.newInstance()
.createClassNewInstance(SecurityService.class);
List list = securityService.checkEmployeeFoPrivilege(permission);
Employee employee = (Employee) request.getSession().getAttribute(
"employee");
boolean flag = false;
for (Object obj : list) {
if (employee.getId().equals((String) obj)) {
flag = true;
}
}
return flag;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
2. 实现Dao与Service,Service与Servlet之间的解耦:
写一个工厂类,如:
XxxDaoFactory中有一个静态方法newInstance()用于得到该工厂类的实例。提供一个方法用于得到目标类的实例对象。如:
XxxDaogetXxxDao(Class clazz) 传进来的class为目标类的实现的接口。通过这个Class得到className,然后通过这个Name值拿到配置文件中的这个Name对应的目标类全名称。
代码如下:
public class ClassFactory {
private static final ClassFactory factory = new ClassFactory();
private Properties prop = new Properties();
private ClassFactory() {
try {
prop.load(ClassFactory.class.getClassLoader().getResourceAsStream(
"classConfig.properties"));
} catch (IOException e) {
throw new RuntimeException("类工厂读取配置文件失败");
}
}
public static ClassFactory newInstance() {
return factory;
}
public <T> T createClassNewInstance(Class<T> classType) {
String name = classType.getSimpleName();
String className = prop.getProperty(name);
try {
return (T) Class.forName(className).newInstance();
} catch (Exception e) {
throw new RuntimeException("类工厂创建类对象失败");
}
}
}