Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
cn.yangjunda.servlet.DispatcherServlet Maven / Gradle / Ivy
package cn.yangjunda.servlet;
import cn.yangjunda.annotation.*;
import cn.yangjunda.multipart.MultipartFile;
import cn.yangjunda.multipart.commons.CommonsMultipartFile;
import cn.yangjunda.util.*;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.math.BigDecimal;
import java.util.*;
import java.util.Map.Entry;
/**请求几种处理类
* @author juanda
*
*/
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1378531571714153483L;
/** 要扫描的包,只有在这个包下并且加了注解的才会呗扫描到 */
private static String PACKAGE = null;
private static final String CONTROLLER_KEY = "controller";
private static final String METHOD_KEY = "method";
private static final String ENTRY_KEY = "entry";
/** 存放Controller中url和方法的对应关系,格式:{url:{controller:实例化后的对象,method:实例化的方法}} */
private static Map> urlMethodMapping = new HashMap>();
private Map handlerMapping = new HashMap<>();
private Set> classes;
private Configuration configuration;
// 上传文件存储目录
private static final String UPLOAD_DIRECTORY = "upload";
// 上传配置
private static final int MEMORY_THRESHOLD = 1024 * 1024 * 3; // 3MB
private static final int MAX_FILE_SIZE = 1024 * 1024 * 40; // 40MB
private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 50; // 50MB
public DispatcherServlet() {
super();
}
/**
* 初始化方法,用于实例化扫描到的对象,并做注入和url映射(注:该方法逻辑上已经判断了,只执行一次)
*/
@Override
public void init(ServletConfig config) throws ServletException {
// 只处理一次
if (urlMethodMapping.size() > 0) {
return;
}
long startTime=System.currentTimeMillis();
System.err.println(new Date()+" cn.yangjunda.servlet.DispatcherServlet init");
System.err.println("INFO: juanda-mvc 初始化开始");
XMLReader xmlReader = new XMLReader();
xmlReader.readXML();
configuration = xmlReader.getConfiguration();
System.err.println(new Date()+" cn.yangjunda.servlet.DispatcherServlet init");
System.err.println("INFO: juanda-mvc 读取XML配置文件");
PACKAGE = configuration.getPackagePath();
if(PACKAGE==null){
System.err.println(new Date()+" cn.yangjunda.servlet.DispatcherServlet init");
System.err.println("INFO: juanda-mvc 读取properties配置文件");
PACKAGE = PropertiesUtil.getProperty("packagePath");
}
if(StringUtils.isEmpty(PACKAGE)){
throw new RuntimeException("配置文件中不存在packagePath");
}
// 开始扫描包下全部class文件
System.err.println(new Date()+" cn.yangjunda.servlet.DispatcherServlet init");
System.err.println("INFO: juanda-mvc 开始扫描包");
classes = ClassTools.getClasses(PACKAGE);
// 存放Controller和Service的Map,格式:{beanName:实例化后的对象}
Map instanceNameMap = new HashMap();
// 存放Service接口类型与接口实例对象的Map,格式:{Service.instance.class:实现类实例化后的对象}
Map, Object> instanceTypeMap = new HashMap, Object>();
// 组装instanceMap
buildInstanceMap(classes, instanceNameMap, instanceTypeMap);
// 开始注入
doIoc(instanceNameMap, instanceTypeMap);
// 注入完之后开始映射url和method
buildUrlMethodMapping(instanceNameMap, urlMethodMapping);
long endTime=System.currentTimeMillis();
System.err.println(new Date()+" cn.yangjunda.servlet.DispatcherServlet init");
System.err.println("INFO: juanda-mvc 初始化成功 持续时间:"+(endTime-startTime)+"ms");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 完整路径
String url = req.getRequestURI();
// 跟路径
String path = req.getContextPath();
// 计算出method上配置的路径,如果用户写了多个"///",只保留一个
String finallyUrl = url.replace(path, "").replaceAll("/+", "/");
// 取出这个url对应的Controller和method
Map map = urlMethodMapping.get(finallyUrl);
if (map != null) {
Method method = (Method) map.get(METHOD_KEY);
Entry entry = (Entry) map.get(ENTRY_KEY);
Class> clazz = entry.getValue().getClass();
if(!handleHttpRequestMethod(req,resp,method)){
return;
}
Object object;
try {
String[] paramNames = ASMGetRealNameUtil.getMethodParameterNamesByAsm4(clazz,method);
// 封装需要注入的参数
List paramValue = buildParamObject(req, resp, method,paramNames);
// 没有参数的场合
if (paramValue.size() == 0) {
object = method.invoke(map.get(CONTROLLER_KEY));
}else {
// 有参数的场合
object = method.invoke(map.get(CONTROLLER_KEY), paramValue.toArray());
}
if(method.isAnnotationPresent(JuandaResponseBody.class)){
ResponseJsonUtil.json(resp,object);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("juanda-mvc 执行url对应的method失败!");
}
}else {
if(Objects.equals(url, "/") ||path.contains("html")||path.contains("xhtml")||path.contains("jsp")){
return;
}else {
// throw new RuntimeException("请求地址不存在!");
}
}
}
/**
* 封装需要注入的参数
* @param req
* @param resp
* @param method
* @return
*/
private List buildParamObject(HttpServletRequest req, HttpServletResponse resp, Method method, String[] paramNames) {
// 封装需要注入的参数,目前只支持request和response以及加了@RequestParam标签的基本数据类型的参数注入
Parameter[] parameters = method.getParameters();
List paramValue = new ArrayList();
int i = 0;
for (Parameter parameter : parameters) {
// 当前参数有别名注解并且别名不为空
if(parameter.isAnnotationPresent(RequestParam.class) && !parameter.getAnnotation(RequestParam.class).value().isEmpty()){
// 我们获取
String value = req.getParameter(parameter.getAnnotation(RequestParam.class).value());
if(value==null&&(!"\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n".equals(parameter.getAnnotation(RequestParam.class).defaultValue()))){
value = parameter.getAnnotation(RequestParam.class).defaultValue();
}
if(parameter.getAnnotation(RequestParam.class).required()){
if(value==null){
throw new NullPointerException("字段:"+parameter.getAnnotation(RequestParam.class).value()+"为必须的,值不能为空");
}
}
Object o = null;
try {
o = adapter(parameter.getType(),value.trim(),req);
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}catch (NullPointerException e){
o = null;
}
paramValue.add(o);
}else if(parameter.isAnnotationPresent(RequestObject.class) && !parameter.getAnnotation(RequestObject.class).value().isEmpty()){
// 我们获取
try {
String classname = null;
String name = null;
String className = null;
String paramsName = null;
for (Class> clasz : classes) {
name = clasz.getName();
className = name.substring((clasz.getName().lastIndexOf(".") + 1), clasz.getName().length()).trim();
paramsName= parameter.getAnnotation(RequestObject.class).value().trim().substring(0, 1).toUpperCase() + parameter.getAnnotation(RequestObject.class).value().substring(1);
if(Objects.equals(className, paramsName)){
classname = clasz.getName();
}
}
paramValue.add(AutoPackObjectUtil.getObject(req,Class.forName(classname)));
} catch (Exception e) {
throw new RuntimeException("开始注入对象时出现了异常");
}
}else if (parameter.getParameterizedType().getTypeName().contains("HttpServletRequest")) {
paramValue.add(req);
}else if (parameter.getParameterizedType().getTypeName().contains("HttpServletResponse")) {
paramValue.add(resp);
}else if (parameter.getParameterizedType().getTypeName().contains("HttpSession")) {
paramValue.add(req.getSession());
}else if (parameter.getParameterizedType().getTypeName().contains("MultipartFile")) {
// 配置上传参数
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置内存临界值 - 超过后将产生临时文件并存储于临时目录中
factory.setSizeThreshold(MEMORY_THRESHOLD);
// 设置临时存储目录
factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置最大文件上传值
upload.setFileSizeMax(MAX_FILE_SIZE);
// 设置最大请求值 (包含文件和表单数据)
upload.setSizeMax(MAX_REQUEST_SIZE);
MultipartFile multipartFile = null;
try {
// 解析请求的内容提取文件数据
List formItems = upload.parseRequest(req);
if (formItems != null && formItems.size() > 0) {
FileItem item = formItems.get(0);
// 迭代表单数据
// 处理不在表单中的字段
if (!item.isFormField()) {
multipartFile = new CommonsMultipartFile(item);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
paramValue.add(multipartFile);
}else{
String value = req.getParameter(paramNames[i]);
Object o = null;
try {
o = adapter(parameter.getType(),value.trim(),req);
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}catch (NullPointerException e){
o = null;
}
paramValue.add(o);
}
i++;
}
return paramValue;
}
/**
* 注入完之后开始映射url和method
* @param instanceMap
* @param urlMethodMapping
*/
private void buildUrlMethodMapping(Map instanceMap,
Map> urlMethodMapping) {
// 注入完之后开始映射url和method
// 组装urlMethodMapping
for (Entry entry : instanceMap.entrySet()) {
// 迭代出所有的url
String parenturl = "";
// 判断Controller上是否加了requestMapping
if (entry.getValue().getClass().isAnnotationPresent(JuandaRequestMapping.class)) {
parenturl = entry.getValue().getClass().getAnnotation(JuandaRequestMapping.class).value();
}
// 取出全部的method
Method[] methods = entry.getValue().getClass().getMethods();
// 迭代全部的方法,检查哪些方法上加了requestMaping注解
for (Method method : methods) {
if (method.isAnnotationPresent(JuandaRequestMapping.class)) {
StringBuffer sb = new StringBuffer();
for(int i = 0; i < method.getParameters().length; i++){
if(i!=method.getParameters().length-1){
sb.append(method.getParameters()[i]).append(",");
}else {
sb.append(method.getParameters()[i]);
}
}
// 得到一个完整的url请求
String url = parenturl + "/" + method.getAnnotation(JuandaRequestMapping.class).value();
url = url.replaceAll("/+", "/");
System.err.println(new Date()+" cn.yangjunda.servlet.DispatcherServlet buildUrlMethodMapping");
System.err.println("INFO: Mapped \"{["+url+"],methods=["+method.getAnnotation(JuandaRequestMapping.class).method().toString()+"]}\" onto public "+method.getName()+" ("+sb.toString()+")");
Map value = new HashMap<>();
value.put(CONTROLLER_KEY, entry.getValue());
value.put(METHOD_KEY, method);
value.put(ENTRY_KEY,entry);
urlMethodMapping.put(url, value );
}
}
}
}
/**
* 根据实例Map开始注入
* @param instanceMap
*/
private void doIoc(Map instanceMap, Map, Object> instanceTypeMap) {
// 开始注入,我们只对加了@Controller和@Service标签中的,属性加了@autowired的进行注入操作
for (Entry entry : instanceMap.entrySet()) {
// 取出全部的属性
Field[] fields = entry.getValue().getClass().getDeclaredFields();
// 循环属性校验哪些是加了@autowired注解的
for (Field field : fields) {
field.setAccessible(true);// 可访问私有属性
// 有注解的时候
if (field.isAnnotationPresent(JuandaAutowired.class)) {
// 没有配别名注入的时候
if (field.getAnnotation(JuandaAutowired.class).value().isEmpty()) {
// 直接获取
try {
// 根据类型来获取他的实现类
Object object = instanceTypeMap.get(field.getType());
field.set(entry.getValue(), object);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException("开始注入时出现了异常");
}
} else {
try {
// 将被注入的对象
Object object = instanceMap.get(field.getAnnotation(JuandaAutowired.class).value());
field.set(entry.getValue(), object);
} catch (Exception e) {
throw new RuntimeException("开始注入时出现了异常");
}
}
}
}
}
}
/**
* 组装instanceMap
* @param classes
* @param instanceMap
*/
private void buildInstanceMap(Set> classes, Map instanceMap, Map, Object> instanceTypeMap) {
// 开始循环全部class
for (Class> clasz : classes) {
// 组装instanceMap
// 判断是否是是加了Controller注解的java对象
if (clasz.isAnnotationPresent(JuandaController.class)) {
try {
// 实例化对象
Object obj = clasz.newInstance();
JuandaController controller = clasz.getAnnotation(JuandaController.class);
// 如果没有设置别名,那么用类名首字母小写做key
if (controller.value().isEmpty()) {
instanceMap.put(firstLowerName(clasz.getSimpleName()), obj);
}else{
// 如果设置了别名那么用别名做key
instanceMap.put(controller.value(), obj);
}
} catch (Exception e) {
throw new RuntimeException("初始化instanceMap时在处理Controller注解时出现了异常");
}
}else if(clasz.isAnnotationPresent(JuandaService.class)) {
// 实例化对象
Object obj = null;
try {
// 实例化对象
obj = clasz.newInstance();
JuandaService service = clasz.getAnnotation(JuandaService.class);
// 如果没有设置别名,那么用类名首字母小写做key
if (service.value().isEmpty()) {
instanceMap.put(firstLowerName(clasz.getSimpleName()), obj);
}else{
// 如果设置了别名那么用别名做key
instanceMap.put(service.value(), obj);
}
} catch (Exception e) {
throw new RuntimeException("初始化instanceMap时在处理Service注解时出现了异常");
}
// 实现的接口数组
Class>[] interfaces = clasz.getInterfaces();
for (Class> class1 : interfaces) {
if (instanceTypeMap.get(class1) != null) {
throw new RuntimeException(class1.getName() + "接口不能被多个类实现!");
}
instanceTypeMap.put(class1, obj);
}
}else {
if(configuration.getAutowire()){
Object obj = null;
try {
obj = clasz.newInstance();
Class>[] interfaces = clasz.getInterfaces();
for (Class> class1 : interfaces) {
System.err.println(new Date()+" cn.yangjunda.servlet.DispatcherServlet bean封装");
System.err.println("INFO: juanda-mvc "+configuration.getBeans().get(class1.getName())+"->"+class1.getName());
if(configuration.getBeans().get(class1.getName())!=null){
if (instanceTypeMap.get(class1) != null) {
throw new RuntimeException(class1.getName() + "接口不能被多个类实现!");
}
instanceTypeMap.put(class1, obj);
}
}
} catch (InstantiationException e) {
// e.printStackTrace();
} catch (IllegalAccessException e) {
// e.printStackTrace();
}
}
}
}
}
/**
* 首字母小写
* @param name
* @return
*/
private String firstLowerName(String name) {
name = name.substring(0, 1).toLowerCase() + name.substring(1);
return name;
}
/**
* url请求拦截器
* @param req
* @param resp
* @param method
* @return
*/
private boolean handleHttpRequestMethod(HttpServletRequest req, HttpServletResponse resp ,Method method){
if(method.getAnnotation(JuandaRequestMapping.class).method().length>0){
RequestMethod[] requestMethods = method.getAnnotation(JuandaRequestMapping.class).method();
boolean flag = false;
for (int i = 0;i paramType, String value,HttpServletRequest req) throws InvocationTargetException, IllegalAccessException {
Object object = null;
if (paramType == String.class) {
object = value;
} else if (paramType == Integer.class) {
if(StringUtils.isBlank(value)){
object=null;
}else {
object = Integer.valueOf(value);
}
} else if(paramType == int.class){
object = Integer.parseInt(value);
} else if (paramType == Long.class || paramType == long.class) {
object = Long.parseLong(value);
} else if (paramType == Boolean.class || paramType == boolean.class) {
object = Boolean.parseBoolean(value);
} else if (paramType == Short.class || paramType == short.class) {
object = Short.parseShort(value);
} else if (paramType == Float.class || paramType == float.class) {
object = Float.parseFloat(value);
} else if (paramType == Double.class || paramType == double.class) {
object = Double.parseDouble(value);
} else if (paramType == BigDecimal.class) {
object = new BigDecimal(value);
} else if (paramType == Character.class || paramType == char.class) {
char[] cs = value.toCharArray();
if (cs.length > 1) {
throw new IllegalArgumentException("参数长度太大");
}
object = value.toCharArray()[0];
} else if(classes.contains(paramType)){
object = AutoPackObjectUtil.getObject(req,paramType);
}
return object;
}
}