1. 映射请求-映射动态资源-参数处理
      服务器接收参数后
      需要按照映射关系调用controller的方法,同时将获取的请求参数,以方法参数的形式传递
      controller方法在接收参数时,希望框架可以按需求实现类型转换
      框架在接收参数,传递参数中,还需按照controller的需求要处理参数
      controller方法的参数列表
      public void t1(String bname,@RequestParam(“num”)int num , int[] nums , HttpServletRequest req , Car car,MuliptartFile excel)

    2. 响应
      框架参数处理完毕后,就可以根据映射关系调用controller方法,传参
      controller中获得参数后的业务处理,就有具体的业务程序完成(controller,service,dao)
      业务程序处理完毕后,需要响应
      直接响应
      直接响应文本字符串
      直接响应集合对象(需要转换成json格式的字符串再响应)
      间接响应
      转发 (携带数据)
      重定向 (携带数据)
      原来响应直接在业务程序中完成
      现在响应由框架完成
      框架实现哪种响应,需要由业务程序告知
      业务程序如何告知框架,需要按照框架的规则告知
      1. 响应内容以返回值的形式返回给框架
      2. 如果是间接响应,直接返回值
      如果不需要携带数据
      return “05.jsp” 转发
      return “redirect:05.jsp” 重定向
      如果需要携带数据
      返回一个框架提供ModelAndView对象 ```java package org.duyi.web7;

    import java.util.HashMap; import java.util.Map; import java.util.Set;

    public class ModelAndView { private String viewName ;// 05.jsp //request.setAttribute(key1,value1); //request.setAttribute(key2,value2); //request.setAttribute(key3,value3); private Map values = new HashMap<>();//存数据

    1. public String getViewName() {
    2. return viewName;
    3. }
    4. public void setViewName(String viewName) {
    5. this.viewName = viewName;
    6. }
    7. public void addObject(String key,Object value){
    8. values.put(key,value) ;
    9. }
    10. public Object getObject(String key){
    11. return values.get(key) ;
    12. }
    13. public Set<String> getObjectNames(){
    14. return values.keySet() ;
    15. }

    }

    1. * 转发: 数据会request.setAttribute()<br /> * 重定向:数据会以?的形式跟在url的后面 (只支持String)<br /> 3. 如果是直接响应,在返回值同时,需要为方法增加一个@ResponseBody的注解<br />只表示一种状态不需要属性
    2. ```java
    3. package org.duyi.web7.annotation;
    4. import java.lang.annotation.ElementType;
    5. import java.lang.annotation.Retention;
    6. import java.lang.annotation.RetentionPolicy;
    7. import java.lang.annotation.Target;
    8. @Target(ElementType.METHOD) //在方法上写
    9. @Retention(RetentionPolicy.RUNTIME)
    10. public @interface ResponseBody {
    11. }
    1. * 如果返回Stringintdouble等简单类型,直接以String返回<br /> * 如果是其他类型,则认为需要转换成json
    1. package com.controller;
    2. import com.domain.Car;
    3. import org.duyi.web7.ModelAndView;
    4. import org.duyi.web7.MulitpartFile;
    5. import org.duyi.web7.annotation.Controller;
    6. import org.duyi.web7.annotation.RequestMapping;
    7. import org.duyi.web7.annotation.RequestParam;
    8. import org.duyi.web7.annotation.ResponseBody;
    9. import javax.servlet.http.HttpServletRequest;
    10. @Controller
    11. public class TestController {
    12. //test1
    13. public void t1(){
    14. System.out.println("测试1");
    15. }
    16. //test11
    17. public void t1(int i,String s){}
    18. //test2
    19. @RequestMapping("/test2")
    20. public void t2(@RequestParam("cname")String s , @RequestParam("price") int[] price,Car car, HttpServletRequest req){
    21. //request
    22. }
    23. @RequestMapping("/test3")
    24. public void t3(Car car){
    25. System.out.println(car);
    26. }
    27. @RequestMapping("/test4")
    28. public void t4(@RequestParam("cname") String cname , @RequestParam("file") MulitpartFile file){
    29. System.out.println(cname);
    30. }
    31. @RequestMapping("/test5")
    32. public String t5(){
    33. return "07.jsp" ;
    34. }
    35. @RequestMapping("/test6")
    36. public ModelAndView t6(){
    37. ModelAndView mv = new ModelAndView();
    38. mv.setViewName("07.jsp");
    39. mv.addObject("cname","benz");
    40. mv.addObject("price",400000);
    41. return mv ;
    42. }
    43. @RequestMapping("/test7")
    44. public ModelAndView t7(){
    45. ModelAndView mv = new ModelAndView();
    46. mv.setViewName("redirect:07.jsp");
    47. mv.addObject("cname","benz");
    48. mv.addObject("price",400000);
    49. return mv ;
    50. }
    51. @RequestMapping("/test8")
    52. @ResponseBody
    53. public String t8(){
    54. return "hello" ;
    55. }
    56. @RequestMapping("/test9")
    57. @ResponseBody
    58. public Car t9(){
    59. Car car = new Car(1,"audi","white",50000);
    60. return car ;
    61. }
    62. }
    1. package org.duyi.web7;
    2. import com.alibaba.fastjson.JSON;
    3. import org.apache.commons.fileupload.FileItem;
    4. import org.apache.commons.fileupload.FileUploadException;
    5. import org.apache.commons.fileupload.disk.DiskFileItemFactory;
    6. import org.apache.commons.fileupload.servlet.ServletFileUpload;
    7. import org.dom4j.Document;
    8. import org.dom4j.DocumentException;
    9. import org.dom4j.Element;
    10. import org.dom4j.io.SAXReader;
    11. import org.duyi.web7.annotation.Controller;
    12. import org.duyi.web7.annotation.RequestMapping;
    13. import org.duyi.web7.annotation.RequestParam;
    14. import org.duyi.web7.annotation.ResponseBody;
    15. import javax.servlet.ServletException;
    16. import javax.servlet.http.HttpServlet;
    17. import javax.servlet.http.HttpServletRequest;
    18. import javax.servlet.http.HttpServletResponse;
    19. import javax.servlet.http.HttpSession;
    20. import java.io.*;
    21. import java.lang.reflect.InvocationTargetException;
    22. import java.lang.reflect.Method;
    23. import java.lang.reflect.Parameter;
    24. import java.util.*;
    25. public class DispatcherServlet extends HttpServlet {
    26. /*
    27. 缓存请求映射信息
    28. key = "/test1"
    29. value = mappingInfo{目标对象,目标方法}
    30. */
    31. Map<String,MappingInfo> mappingInfoMap = new HashMap<>();
    32. /*
    33. 单实例存储controller对象
    34. key="com.controller.TestController"
    35. value= new Object
    36. */
    37. Map<String,Object> controllerMap = new HashMap<>();
    38. /**
    39. * 读取各种配置信息
    40. * (目前只有请求映射信息)
    41. * @throws ServletException
    42. */
    43. @Override
    44. public void init() throws ServletException {
    45. //目前配置信息来自于两个部分,而且两个部分都可能存在
    46. String xmlPath = super.getInitParameter("classpath");
    47. if(xmlPath != null && !"".equals(xmlPath)){
    48. //指定了配置文件,需要读取配置文件
    49. readXml(xmlPath);
    50. }
    51. String packagePath = super.getInitParameter("controller-scan") ;
    52. if(packagePath != null && !"".equals(packagePath)){
    53. try {
    54. //指定了包路径,需要读取包下类中的注解信息
    55. readAnnotation(packagePath);
    56. } catch (ClassNotFoundException e) {
    57. e.printStackTrace();
    58. } catch (IllegalAccessException e) {
    59. e.printStackTrace();
    60. } catch (InstantiationException e) {
    61. e.printStackTrace();
    62. }
    63. }
    64. }
    65. //读取xml配置文件
    66. public void readXml(String path){
    67. //path="mvc.xml"
    68. //D:\ideaworkspace2\web-demo\out\artifacts\web_demo_war_exploded\WEB-INF\classes\mvc.xml
    69. path = Thread.currentThread().getContextClassLoader()
    70. .getResource(path).getPath();
    71. try {
    72. InputStream is = new FileInputStream(path) ;
    73. //使用dom,sax读取xml内容
    74. SAXReader reader = new SAXReader() ;
    75. Document document = reader.read(is) ;
    76. //解析mapping标签
    77. parseMappingElement(document);
    78. //解析multipart-encoding
    79. parseMultipartEncodingElement(document);
    80. //解析其他标签
    81. } catch (FileNotFoundException e) {
    82. e.printStackTrace();
    83. } catch (DocumentException e) {
    84. e.printStackTrace();
    85. } catch (IllegalAccessException e) {
    86. e.printStackTrace();
    87. } catch (InstantiationException e) {
    88. e.printStackTrace();
    89. } catch (ClassNotFoundException e) {
    90. e.printStackTrace();
    91. } catch (NoSuchMethodException e) {
    92. e.printStackTrace();
    93. }
    94. }
    95. private String multipartEncoding ;
    96. //读取<multipart-encoding>标签
    97. private void parseMultipartEncodingElement(Document document){
    98. Element mulipartEncodingElement = (Element) document.selectSingleNode("mvc/multipart-encoding");
    99. if(mulipartEncodingElement == null)
    100. return ;
    101. multipartEncoding = mulipartEncodingElement.getText() ;
    102. }
    103. //读取xml中<mapping>请求映射信息
    104. private void parseMappingElement(Document document) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException {
    105. //按照标签的嵌套规则,找到需要的所有mapping标记
    106. List<Element> mappingElements = document.selectNodes("mvc/mapping") ;
    107. for(Element mappingElement : mappingElements ){
    108. /*
    109. 获得标签指定的属性值
    110. 标签中记载着请求与响应对应关系
    111. 此时(初始化)获得这个对应关系,不是次使用
    112. 后面请求的时候用
    113. 所以需要存储起来,组成对象
    114. */
    115. String path = mappingElement.attributeValue("path") ;
    116. String classname = mappingElement.attributeValue("class") ; // com.controller.TestController
    117. String methodname = mappingElement.attributeValue("method") ; // t1
    118. //反射创建目标对象
    119. Class clazz = Class.forName(classname) ;
    120. Object controller = getSingleController(classname);
    121. //通过反射,根据方法名获得方法对象 t1() , t2(int , String)
    122. //获得mapping标签的子标签<type> 存储目标方法对应的参数列表
    123. List<Element> typeElements = mappingElement.selectNodes("type") ;
    124. //创建一个与配置文件中<type>数量相同的Class数组,准备装载目标方法对应的参数列表类型
    125. Class[] types = new Class[typeElements.size()] ;
    126. int i = 0 ;
    127. for(Element typeElement : typeElements){
    128. //<type> 获得标签的文本内容 "int"
    129. String typeStr = typeElement.getText() ;
    130. //"int" ->int.class
    131. types[i++] = castStringToClass(typeStr) ;
    132. }
    133. Method method = clazz.getMethod(methodname,types ) ;
    134. MappingInfo info = new MappingInfo(path,controller,method) ;
    135. mappingInfoMap.put(path,info) ;
    136. }
    137. }
    138. /*
    139. * 将字符串表示的类型转换成对应的Class类型
    140. * "int" -> int.class
    141. * "java.lang.String" -> String.class -> Class.forName("java.lang.String")
    142. */
    143. private Class castStringToClass(String typeStr) throws ClassNotFoundException {
    144. if("int".equals(typeStr)){
    145. return int.class;
    146. }
    147. if("long".equals(typeStr)){
    148. return long.class;
    149. }
    150. if("double".equals(typeStr)){
    151. return double.class;
    152. }
    153. //除去8种基本类型,以外的都是引用类型,写的都是全名,反射生成Class , java.lang.Integer
    154. return Class.forName(typeStr) ;
    155. }
    156. public Object getSingleController(String classname) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    157. Class clazz = Class.forName(classname);
    158. Object controller = controllerMap.get(classname);
    159. if(controller == null){
    160. controller = clazz.newInstance() ;
    161. controllerMap.put(classname,controller);
    162. }
    163. return controller ;
    164. }
    165. //读取注解
    166. public void readAnnotation(String packagePath) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    167. //packagePath = "com.controller,com.controller2,.."
    168. //需要框架从指定的2个包中找到请映射的注解
    169. //packagePathArray = {"com.controller","com.controller2"};
    170. String[] packagePathArray = packagePath.split(",") ;
    171. for(String ppath : packagePathArray){
    172. //ppath = "com.controller"
    173. //要想完成反射,只有包路径还不够,还需要类名 com.controller + TestController
    174. //如何获得类名
    175. //不能通过反射获得包中类
    176. //可以通过File操作获得文件夹中的文件名->去掉后缀,就是类名
    177. // "com.controller" -> "com/controller"
    178. String dirPath = ppath.replace(".","/");
    179. // dirPath ="F:\dmc\idea_workspace\web-demo\out\artifacts\web_demo_war_exploded\WEB-INF\classes\com\controller"
    180. try {
    181. dirPath = Thread.currentThread().getContextClassLoader()
    182. .getResource(dirPath).getPath();
    183. }catch(NullPointerException e){
    184. //指定的包路径有错误
    185. System.out.println("logging : package path not found ["+dirPath+"]");
    186. //当前不存在包就不在检索了
    187. continue ;
    188. //throw new FileNotFoundException(dirPath);
    189. }
    190. File dir = new File(dirPath);
    191. //获得文件夹中所有子内容名字 (子文件夹,子文件)
    192. String[] fnames = dir.list() ;
    193. for(String fname : fnames){
    194. //fname="TestController.class
    195. if(fname.endsWith(".class")){
    196. int i = fname.indexOf(".") ;
    197. //className="TestController"
    198. String className = fname.substring(0,i);
    199. //className = "com.controller.TestController"
    200. className = ppath + "." + className ;
    201. Class clazz = Class.forName(className);
    202. Controller c = (Controller) clazz.getAnnotation(Controller.class);
    203. if(c == null){
    204. //当前包中的这个类没有设置@Controller,类中没有请求映射信息
    205. continue ;
    206. }
    207. //有@Controller,类中有请求映射关系
    208. //遍历类中所有的方法,找到@RequestMapping
    209. Method[] methodArray = clazz.getMethods() ;
    210. for(Method method : methodArray){
    211. RequestMapping rm = method.getAnnotation(RequestMapping.class);
    212. if(rm == null){
    213. continue ;
    214. }
    215. //方法中有@RequestMapping,表示是一个请求映射的方法
    216. String path = rm.value();
    217. Object controller = getSingleController(className);
    218. MappingInfo info = new MappingInfo(path,controller,method) ;
    219. Object obj = mappingInfoMap.get(path);
    220. if(obj != null ){
    221. //当前请求映射关系已经存在
    222. //去重 continue
    223. //覆盖 map.put
    224. //抛出异常 throw new Exception
    225. }
    226. mappingInfoMap.put(path,info) ;
    227. }
    228. }
    229. }
    230. }
    231. }
    232. //-----------------------------------------------------------------------------------------------------------------------------------------------
    233. //------------------------------------初始化处理结束-----------------------------------------------------------------------------------------------
    234. //-----------------------------------------------------------------------------------------------------------------------------------------------
    235. @Override
    236. protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    237. //请求映射,根据请求调用controller的具体方法
    238. //获得请求 /test1
    239. //req.getRequestURL(); // http://localhost:8080/web-demo/test1
    240. String uri = req.getRequestURI() ;// /web-demo/test1
    241. System.out.println(uri);
    242. String root = req.getContextPath() ;// /web-demo
    243. String path = uri.replace(root,""); // /test1
    244. //根据请求找到对应的mappinginfo 映射信息
    245. MappingInfo info = mappingInfoMap.get(path) ;
    246. if(info == null){
    247. //没有找到与之匹配映射请求 (xml和注解)
    248. //没有需要调用的controller和方法
    249. //有可能此次请求的是一些文件资源.html , .css , .js , .jpg
    250. //之前在没有框架的时候,为什么可以访问这些静态文件呢
    251. //原因是tomcat提供了一个专门处理静态资源访问的DefaultServlet
    252. //该servlet处理的请求模式就是 /
    253. //现在我们的DispatcherServlet一般也建议配置成 /
    254. //就会覆盖tomcat自带的DefaultServlet
    255. //就不会再自动处理静态资源了
    256. //就需要框架来处理静态资源
    257. handleStaticResource(path,req,resp);
    258. }else{
    259. try {
    260. //找到映射信息了,就按照映射信息分发请求,调用controller.method
    261. handleDynamicResource(info,req,resp);
    262. } catch (InvocationTargetException e) {
    263. e.printStackTrace();
    264. } catch (IllegalAccessException e) {
    265. e.printStackTrace();
    266. } catch (InstantiationException e) {
    267. e.printStackTrace();
    268. }
    269. }
    270. }
    271. /*
    272. 处理动态资源请求
    273. */
    274. private void handleDynamicResource(MappingInfo info,HttpServletRequest req,HttpServletResponse resp) throws InvocationTargetException, IllegalAccessException, InstantiationException, IOException, ServletException {
    275. //获得参数
    276. Map<String,Object> paramMap = receiveParams(req);
    277. //处理参数
    278. Object[] paramValues = handleParam(paramMap,info,req,resp) ;
    279. //调用mappinginfo中的对象的方法,传递参数
    280. Object result = info.getMethod().invoke( info.getController() , paramValues ) ;
    281. //根据result返回值,实现响应
    282. handleResponse(result,info.getMethod(),req,resp);
    283. }
    284. private void handleResponse(Object result,Method method,HttpServletRequest req,HttpServletResponse resp) throws IOException, ServletException {
    285. if(result == null){
    286. //不需要框架响应
    287. return ;
    288. }
    289. ResponseBody rb = method.getAnnotation(ResponseBody.class);
    290. if(rb != null){
    291. //有@ResponseBody 直接响应
    292. if(
    293. result instanceof String ||
    294. result instanceof Integer ||
    295. result instanceof Long ||
    296. result instanceof Boolean){
    297. //简单类型,都变成字符串,直接响应
    298. resp.getWriter().write(result.toString());
    299. }else{
    300. //不是简单类型,就是集合对象,需要转换成json再响应
    301. // 直接把返回值转换为json
    302. String json = JSON.toJSONString(result) ;
    303. resp.setContentType("text/json"); //类型转换
    304. resp.getWriter().write(json); //响应回去
    305. }
    306. }else{
    307. // 间接响应
    308. if(result instanceof String){
    309. //不需要携带数据
    310. String _result = (String) result;
    311. if(_result.startsWith("redirect:")){
    312. //重定向 "redirect:05.jsp"
    313. // "05.jsp"
    314. _result = _result.replace("redirect:","");
    315. resp.sendRedirect(_result);
    316. }else{
    317. //转发 "05.jsp"
    318. req.getRequestDispatcher(_result).forward(req,resp);
    319. }
    320. }else{
    321. //就是ModelAndView,需要携带数据
    322. ModelAndView _result = (ModelAndView) result;
    323. // path="05.jsp" / "redirect:05.jsp"
    324. String path = _result.getViewName() ;
    325. if(path.startsWith("redirect:")){
    326. //重定向携带数据 05.jsp?...
    327. path = path.replace("redirect:","");
    328. path+="?" ;
    329. Set<String> names = _result.getObjectNames() ;
    330. for(String name : names){
    331. Object value = _result.getObject(name);
    332. path+=name+"="+value+"&";
    333. }
    334. //05.jsp?a=1&b=2&c=3
    335. resp.sendRedirect(path);
    336. }else{
    337. //转发携带数据,
    338. //req.setAttribute(name,value)
    339. Set<String> names = _result.getObjectNames() ;
    340. for(String name : names){
    341. Object value = _result.getObject(name);
    342. req.setAttribute(name,value);
    343. }
    344. req.getRequestDispatcher(path).forward(req,resp);
    345. }
    346. }
    347. }
    348. }
    349. /*
    350. 按照请求映射关系要调用的那个目标方法
    351. 获得目标方法的参数列表
    352. 根据参数列表获得所需要的参数
    353. 并将参数组装Object[]中
    354. */
    355. private Object[] handleParam(Map<String,Object> paramMap,MappingInfo info,HttpServletRequest req , HttpServletResponse resp) throws IllegalAccessException, InstantiationException, InvocationTargetException {
    356. Method method = info.getMethod() ;
    357. Parameter[] parameters = method.getParameters() ;
    358. //创建一个与方法参数列表同长度的数组装载参数数据(实参)
    359. Object[] paramValues = new Object[ parameters.length ] ;
    360. int i = 0 ;
    361. for(Parameter parameter : parameters){
    362. RequestParam rp = parameter.getAnnotation(RequestParam.class);
    363. Class paramType = parameter.getType() ;
    364. if(rp != null){
    365. //证明有这个注解 @RequestParam("cname") String cname
    366. //表示需要请求传递的一个叫cname名字的参数
    367. //请求传递的参数之前已经处理过了
    368. //处理后将请求传递的参数存入了paramMap集合中,key=cname,value=[]
    369. String key = rp.value() ;// cname
    370. Object value = paramMap.get(key) ;
    371. if(value == null){
    372. //当前所需要的的参数没有值,默认是null,之间找下一个参数值
    373. i++ ;
    374. continue ;
    375. }
    376. //如果参数值存在,起初只有2种表现形成 String[] , MulitpartFile[]
    377. //将此次需要的参数value,转换成方法中定义的需要参数类型
    378. paramValues[i++] = castType(value,paramType);
    379. }else{
    380. //没有@RequestParam注解
    381. //可能是request,response,session,domain(组装参数User,Car,Goods)
    382. if(paramType == HttpServletRequest.class){
    383. paramValues[i++] = req ;
    384. }else if(paramType == HttpServletResponse.class){
    385. paramValues[i++] = resp ;
    386. }else if(paramType == HttpSession.class){
    387. paramValues[i++] = req.getSession() ;
    388. }else{
    389. //是一个domain类型,假设是paramType = Car.class
    390. //将此次请求的多个参数,最终组成一个car对象
    391. Object paramObject = paramType.newInstance() ; //new Car()
    392. //通过反射获得对象中的属性名,根据属性名找到与之同名的参数,为属性赋值
    393. //为了更好的符合java封装的特性,不建议通过反射找属性,建议通过反射找对应的set方法
    394. Method[] methods = paramType.getMethods() ;
    395. for(Method m : methods){
    396. String mname = m.getName() ;
    397. if(mname.startsWith("set")){
    398. //是一个set方法,有对应的属性 setCname --> cname
    399. String key = mname.substring(3) ;//去掉set-->Cname
    400. key = key.substring(0,1).toLowerCase() + key.substring(1) ;// cname
    401. Object value = paramMap.get(key) ;
    402. if(value == null){
    403. i++ ;
    404. continue ;
    405. }
    406. //根据domain的set方法(属性名)找到了与之对应的参数
    407. //该参数起初只是String[],MultipartFile[]类型
    408. //需要转换成domain中属性的类型
    409. Class domainParamType = m.getParameterTypes()[0] ; // void setCname(String cname) -> String
    410. Object v = castType(value,domainParamType) ;
    411. m.invoke(paramObject,v) ;// car.setCname(cname);
    412. }
    413. }
    414. //循环结束,找到了所有的set方法,为对象的属性赋值,赋值结束将对象参数保存
    415. paramValues[i++] = paramObject;
    416. }
    417. }
    418. }
    419. return paramValues ;
    420. }
    421. /*
    422. 将原始类型的参数数据,转换成目标方法所需要的类型
    423. 原始类型:String[] , MulipatrFile[]
    424. 目标类型:int,long,double,String,int[],long[],String[],Integer,Integer[],
    425. MultiparFile , MultipartFile[]
    426. */
    427. private Object castType(Object value , Class paramType){
    428. if(paramType == String.class){
    429. String str = ((String[])value)[0] ;
    430. return str ;
    431. }
    432. if(paramType == int.class || paramType==Integer.class){
    433. String str = ((String[])value)[0] ;
    434. int num = Integer.parseInt(str) ;
    435. return num ;
    436. }
    437. if(paramType == long.class || paramType==Long.class){
    438. String str = ((String[])value)[0] ;
    439. long num = Long.parseLong(str) ;
    440. return num ;
    441. }
    442. if(paramType == double.class || paramType==Double.class){
    443. String str = ((String[])value)[0] ;
    444. double num = Double.parseDouble(str) ;
    445. return num ;
    446. }
    447. if(paramType == String[].class){
    448. return value ;
    449. }
    450. //url?cname=1&cname=2&cname3 =》框架会存储成数组[1,2,3]
    451. if(paramType == int[].class){
    452. String[] ss = (String[])value ;
    453. int[] nums = new int[ss.length];
    454. for(int j=0;j< ss.length;j++){
    455. nums[j] = Integer.parseInt(ss[j]);
    456. }
    457. return nums ;
    458. }
    459. if(paramType == Integer[].class){
    460. String[] ss = (String[])value ;
    461. Integer[] nums = new Integer[ss.length];
    462. for(int j=0;j< ss.length;j++){
    463. nums[j] = Integer.valueOf(ss[j]);
    464. }
    465. return nums ;
    466. }
    467. if(paramType == MulitpartFile.class){
    468. return ((MulitpartFile[])value)[0];
    469. }
    470. if(paramType == MulitpartFile[].class)
    471. return value ;
    472. return null ;
    473. }
    474. /*
    475. * 接收请求传递从参数
    476. * 将参数处理后装入map
    477. * map.key就是请求传递参数key <input type="uname" /> map.key=uname
    478. * map.value 可能是一个 String[] 也可能是一个 文件[] -> Object表示
    479. */
    480. private Map<String,Object> receiveParams(HttpServletRequest req){
    481. Map<String,Object> paramMap = new HashMap<>();
    482. //参数有2种可能 (普通请求,文件上传请求)
    483. //如果普通请求按照文件上传方式处理,会抛出异常
    484. //如果文件上传请求按照普通请求处理会得不到参数
    485. try{
    486. //假设是文件上传方式传递参数
    487. DiskFileItemFactory factory = new DiskFileItemFactory();
    488. ServletFileUpload upload = new ServletFileUpload(factory) ;
    489. //该行会判断是否是文件上传请求,是否配置了enctype="multipart/form-data",如果不是会抛出异常
    490. List<FileItem> fis = upload.parseRequest(req) ;
    491. //确实是一个文件上传的请求,同时因为上一行代码,已经将请求的参数都组成了FileItem对象,装入了List集合
    492. for(FileItem fi : fis){
    493. //拿到了一个参数
    494. if(fi.isFormField()){
    495. // 是一个普通参数,String
    496. String key = fi.getFieldName() ;// <input name="uname" />
    497. String value = fi.getString(multipartEncoding) ;
    498. String[] values = (String[]) paramMap.get(key);
    499. if(values == null){
    500. //还没有存储过当前这个名字的参数
    501. values = new String[]{value} ;
    502. paramMap.put(key,values) ;
    503. }else{
    504. //当前名字的参数之前存储过,将当前的数据装入数组,数组扩容+1
    505. values = Arrays.copyOf(values,values.length+1) ;
    506. values[ values.length-1 ] = value ;
    507. paramMap.put(key,values) ;
    508. }
    509. }else{
    510. // 是一个文件参数
    511. String key = fi.getFieldName() ; // <input type="file" name="excel" />
    512. String fileName = fi.getName() ; //文件名 1.jpg
    513. long size = fi.getSize() ;//获得文件大小
    514. String contentType = fi.getContentType() ; //文件的类型
    515. InputStream is = fi.getInputStream() ;//文件内容
    516. MulitpartFile file = new MulitpartFile(key,fileName,size,contentType,is);
    517. MulitpartFile[] files = (MulitpartFile[]) paramMap.get(key);
    518. if(files == null){
    519. //当前名字的文件参数之前没有
    520. files = new MulitpartFile[]{file} ;
    521. paramMap.put(key,files);
    522. }else{
    523. //之前存储过这个名字的文件参数
    524. files = Arrays.copyOf(files,files.length+1);
    525. files[ files.length-1 ] = file ;
    526. paramMap.put(key,files) ;
    527. }
    528. }
    529. }
    530. }catch(FileUploadException e){
    531. //出现异常表示不是文件上传方式,再按照普通方式处理
    532. Enumeration<String> names = req.getParameterNames();
    533. while(names.hasMoreElements()){
    534. String name = names.nextElement() ; // name="uname"
    535. String[] values = req.getParameterValues(name);
    536. paramMap.put(name,values) ;
    537. }
    538. } catch (UnsupportedEncodingException e) {
    539. e.printStackTrace();
    540. } catch (IOException e) {
    541. e.printStackTrace();
    542. }
    543. return paramMap ;
    544. }
    545. /*
    546. 处理静态资源,在mapping映射信息中没有找到就表示静态资源
    547. */
    548. private void handleStaticResource(String path,HttpServletRequest req,HttpServletResponse resp) throws IOException {
    549. if(path.equals("/")){
    550. //获得/表示的默认资源->/index.html
    551. path = req.getServletPath();
    552. }
    553. //path="/index.html"
    554. //根据请求的相对路径,找到对应文件在服务器端存储的绝对路径
    555. //Thread.currentThread...()获得classes目录下的文件路径
    556. //request.getServletContext().realPath()获得服务器目录下的文件路径
    557. //path ="F:\dmc\idea_workspace\web-demo\out\artifacts\web_demo_war_exploded\index.html"
    558. String fpath = req.getServletContext().getRealPath(path);
    559. File file = new File(fpath) ;
    560. if(!file.exists()){
    561. //能执行当前方法,表示此次请求的不是一个动态资源
    562. //文件不存在,表示此次请求的静态资源不存在
    563. //表示此次没有找到对应的资源
    564. resp.sendError(404,"["+path+"]");
    565. return ;
    566. }
    567. InputStream is = new FileInputStream(file);
    568. OutputStream os = resp.getOutputStream() ;
    569. byte[] bs = new byte[0x100] ;//16*16=256
    570. while(true){
    571. int len = is.read(bs) ;
    572. if(len == -1)break ;
    573. os.write(bs,0,len);
    574. }
    575. os.flush();
    576. is.close();
    577. }
    578. }