最早使用的控制层框架就是struts1 然后是struts2 在之后就是SpringMVC的Controller了。就个人而言感觉Spring的Controller使用
很方便也很简单。所以我们的控制层就模仿Spring的Controller来实现。包括注解、返回页面的方式、以及之后的文件上传都依稀能看到
SpringMVC的身影。并且我们也是用Servlet来实现,真是一个精简版的Spring Controller,哈....
注解
package com.hc.web.annotation;
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.TYPE})
public @interface Controller {
public String path();
}
package com.hc.web.annotation;
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.METHOD})
public @interface MethodMapping {
public String method();
}
控制器类信息
package com.hc.web;
import java.lang.reflect.Method;
import java.util.Map;
public class ControllerClassInfo {
private Class<?> cls;
private String path;
private Map<String,Method> methodMap;
public Class<?> getCls() {
return cls;
}
public void setCls(Class<?> cls) {
this.cls = cls;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public Map<String, Method> getMethodMap() {
return methodMap;
}
public void setMethodMap(Map<String, Method> methodMap) {
this.methodMap = methodMap;
}
}
控制器缓存
package com.hc.web;
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.hc.web.annotation.Controller;
import com.hc.web.annotation.MethodMapping;
/**
* 控制器缓存
* @author chuer
* @date 2014-7-16 下午3:54:57
* @version V1.0
*/
public class ControllerCache {
/*key: path value: ControllerClassInfo*/
private static ConcurrentHashMap<String, ControllerClassInfo> cache = new ConcurrentHashMap<>();
public static final String PAKAGE = "com";//扫描的包名 根据自己的包名进行修改
public static final String PAKAGE_SOURCE = "/com/hc";//扫描的包名 根据自己的包名进行修改
public static final String SECOND_PAKAGE = "com.hc";//扫描的包名 根据自己的包名进行修改
static{
init();
}
private static void init(){
String path = ControllerCache.class.getResource(PAKAGE_SOURCE).getPath();
List<String> classes = new ArrayList<String>();
getAllClasses(new File(path),classes);
for(String p : classes){
try{
Class<?> cls = Class.forName(p);
if(cls.isAnnotationPresent(Controller.class)){
Controller ca = cls.getAnnotation(Controller.class);
if(cache.containsKey(ca.path())){
throw new Exception("duplicate Controller path:"+ca.path());
}
ControllerClassInfo cci = new ControllerClassInfo();
cci.setCls(cls);
cci.setPath(ca.path());
Method[] declaredMethods = cls.getDeclaredMethods();
Map<String,Method> map = new HashMap<>();
for(Method method : declaredMethods){
if(method.isAnnotationPresent(MethodMapping.class)){
MethodMapping mm = method.getAnnotation(MethodMapping.class);
if(map.containsKey(mm.method())){
throw new Exception("duplicate Method name:"+mm.method());
}
map.put(mm.method(), method);
}
}
cci.setMethodMap(map);
cache.put(ca.path(), cci);
}
}catch(Exception e){
e.printStackTrace();
}
}
}
private static void getAllClasses(File file,List<String> files){
if(file.isDirectory()){
File[] listFiles = file.listFiles();
for(File f : listFiles){
getAllClasses(f,files);
}
}else{
if(file.getAbsolutePath().endsWith(".class")){
String substring = file.getAbsolutePath().substring(file.getAbsolutePath().indexOf(PAKAGE));
substring = substring.substring(0, substring.lastIndexOf('.'));
if(substring.contains("/")){
substring = substring.replaceAll("/", ".");
}else{
substring = substring.replaceAll("\\\\", ".");
}
if(substring.contains(SECOND_PAKAGE)){
files.add(substring);
}
}
}
}
public static ControllerClassInfo get(String key){
return cache.get(key);
}
public static void main(String...args){
}
}
返回页面类
package com.hc.web;
public class View {
private String path;
public View(String path){
this.path = path;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
控制器核心类
package com.hc.web;
import java.io.IOException;
import java.lang.reflect.Method;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import com.hc.pool.DBPool;
import com.hc.web.io.MutipartFile;
import com.hc.web.io.UploadFileParse;
/**
*
* @author chuer
* @date 2014-7-16 下午3:55:23
* @version V1.0
*/
@WebServlet(urlPatterns={"*.hc"},loadOnStartup=1)
public class AbstractHcAction extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
public void init() throws ServletException {
DBPool.getInstance();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String methodParam = request.getParameter("method");
String servletPath = request.getServletPath();
ControllerClassInfo controllerClassInfo = ControllerCache.get(servletPath);
try {
Class<?> cls = controllerClassInfo.getCls();
Object newInstance = cls.getConstructor(new Class[]{}).newInstance(new Object[]{});
//调用controller方法
Method method = controllerClassInfo.getMethodMap().get(methodParam);
Object invoke = method.invoke(newInstance, request,response);
if(invoke != null && invoke instanceof View){
View view = (View)invoke;
request.getRequestDispatcher(view.getPath()).forward(request, response);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
具体控制器类
package com.hc.sample.controller;
import java.io.File;
import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.hc.annotation.Inject;
import com.hc.sample.service.UserService;
import com.hc.web.View;
import com.hc.web.annotation.Controller;
import com.hc.web.annotation.MethodMapping;
import com.hc.web.io.MutipartFile;
@Controller(path="/user.hc")
public class UserController {
private UserService userService = TransactionProxyCache.cache.get(UserServiceImpl.class);
@MethodMapping(method="addUser")
public View addUser(HttpServletRequest request, HttpServletResponse response) throws SQLException{
userService.add();
return new View("user.jsp");
}
public void setUserService(UserService userService) {
this.userService = userService;
}
}
测试
把我们这个项目整体部署到tomcat下,因为我们使用WebServlet注解,所以用不着web.xml文件。
然后启动tomcat。再浏览器输入:http://localhost:8080/上下文/user.hc?method=addUser.
查看数据库和页面的变化。对了 webRoot下还得有一个user.jsp。也可以把WebServlet的注解去掉,然后把AbstractHcAction这个servlet配置到web.xml中。效果是一样的。
控制器就完成了, 下面的一章我们做IOC注入。