接口与抽象类
DI&IOC
一句话:本来我接受各种参数来构造一个对象,现在只接受一个参数——已经实例化的对象。
也就是说我对对象的『依赖』是注入进来的,而和它的构造方式解耦了。构造它这个『控制』操作也交给了第三方,也就是控制反转IOC。
IOC:在应用程序中的组件需要获取资源时,传统的方式是组件主动的从容器中获取所需要的资源,在这样的模式下开发人员往往需要知道在具体容器中特定资源的获取方式,增加了学习成本,同时降低了开发效率。
反转控制的思想完全颠覆了应用程序组件获取资源的传统方式:反转了资源的获取方向——改由容器自动的将资源推送给需要的组件,开发人员不需要知道容器是如何创建资源对象的,只需要提供接收资源的方式即可,极大的降低了学习成本,提高了开发的效率。这种行为也称为查找的被动形式。
BeanFactory&ApplicationContext
BeanFactory: bean工厂接口,负责创建bean实例,
容器里保存的所有单例bean其实是一个map。Spring最底层的接口
ApplicationContext:是BeanFactory的子接口。留给程序员使用的ioc容器接口
更多负责容器功能的实现(基于BeanFactory创建好的对象之上)
从容器中获取bean;
包括DI,AOP都是在ApplicationContext接口的这些类下面
Spring模式:工厂模式
Spring泛型依赖注入原理
不管三七二十一
servlet :加注解@servlet
service:加注解@service
dao:加注解@Repository
这相当于在容器中注册这些个类
AOP
描述:将某段代码"动态"的切入到"指定方法"的"指定位置"进行运行的一种编程方式
(其底层就是Java的动态代理)spring对其做了简化书写
场景:
1)、AOP加日志保存到数据库
2)、AOP做权限验证,filter能做的它都能
3)、AOP做安全检查
4)、AOP做事务控制
AOP专业术语:
Java反射
1.示例
1.用户类
package com.lf.entity;
import com.lf.annotation.SetProperty;
import com.lf.annotation.SetTable;
public class UserEntity {
private String userName;
private int userAge;
private final int money = 10000;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getUserAge() {
return userAge;
}
public void setUserAge(int userAge) {
this.userAge = userAge;
}
//借钱方法
public int getMoney(){
System.out.println("你借了 " + money + "元!");
return money;
}
//还钱方法,单个参数
public void repay(int money){
System.out.println("你还了 " + money + "元!");
}
//还钱方法,多个参数
public void repay(String userName,int money){
System.out.println(userName+ " 还了 " + money + "元!");
}
}
2.测试类
//反射调用方法获取返回值
1)获取类对象Class
2)根据类对象Class获取构造器getConstructor(类<?>... parameterTypes)
3)然后用Constructor. newInstance(Object... initargs)获取实例;传入5)的第一个参数
4) 根据类对象Class获取方法getMethod(String name, 类<?>... parameterTypes)
5)然后用Method.invoke执行方法invoke(Object obj, Object... args)
package com.lf.test;
import java.lang.reflect.Method;
import com.lf.entity.UserEntity;
public class Reflection {
public static void main(String[] args) throws Exception {
Class<?> userClass = Class.forName("com.lf.entity.UserEntity");
UserEntity userEntity = (UserEntity) userClass.newInstance();
//第一种方法:获取对象,直接通过对象调用方法
System.out.println("第一次借钱:");
int money = userEntity.getMoney();
System.out.println("实际拿到钱为: " + money);
System.out.println("------------------------分割线--------------");
//第二种方法:通过方法名获取方法,执行方法
//(无参的示例:借钱)
System.out.println("第二次借钱:");
Method getMoney = userClass.getMethod("getMoney");//得到方法对象
Object money2 = getMoney.invoke(userEntity);//调用借钱方法,得到返回值
System.out.println("实际拿到钱为:" + money2);
System.out.println("------------------------分割线---------------");
//(单个参数的示例:还钱)
System.out.println("第一次还钱:");
Method repay1 = userClass.getMethod("repay",int.class);//得到方法对象,有参的方法需要指定参数类型
repay1.invoke(userEntity,3000);//执行还钱方法,有参传参
System.out.println("------------------------分割线---------------");
//(多个参数的示例:还钱)
System.out.println("第二次还钱:");
Method repay2 = userClass.getMethod("repay", String.class,int.class);//得到方法对象,有参的方法需要指定参数类型
repay2.invoke(userEntity,"小飞",5000);//执行还钱方法,有参传参
}
}
2.反射起源
* 框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
* 反射:将类的各个组成部分封装为其他对象(对象数组),这就是反射机制
*大道至简:类名本身明明就是一个字符串,我想通过对字符串的控制来创建一系列不同的对象,怎么办?不好意思,java语法本身是不提供这个功能的,但是JavaScript就可以定义变量即为对象,且可以为该对象随意添加属性。为了维护java高大上的荣誉,自然是要污蔑javascript的方式是导致js代码混乱的根源之一。可是实际需要这种方法的时候,对javascript批量生产不同object方式又羡慕嫉妒恨,在没有办法的情况下,创立了反射机制,这样就能通过字符串找到需要的类并进行不同对象批量生成。java优雅地再次在功能上碾压了javascript,从此人人都又高兴了起来。
* 获取Class对象的方式:
1.源代码阶段:
Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
* 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
2. Class类对象阶段
类名.class:通过类名的属性class获取
* 多用于参数的传递--被传者
3. Runtime运行阶段
对象.getClass():getClass()方法在Object顶级类中定义着。
* 多用于对象的获取字节码的方式
结论:
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
* Class对象功能:
获取功能:
1. 获取成员变量们
* Field[] getFields() :获取所有public修饰的成员变量
* Field getField(String name)获取指定名称的 public修饰的成员变量
* Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
* Field getDeclaredField(String name)
2. 获取构造方法们
//类<?>:比如String.class
* Constructor<?>[] getConstructors()
* Constructor<T> getConstructor(类<?>... parameterTypes)
* Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
* Constructor<?>[] getDeclaredConstructors()
3. 获取成员方法们:
* Method[] getMethods()
* Method getMethod(String name, 类<?>... parameterTypes)
* Method[] getDeclaredMethods()
* Method getDeclaredMethod(String name, 类<?>... parameterTypes)
4. 获取全类名
* String getName()
*封装的对象
*Field:成员变量
* 操作:
// Object obj :Field对象所在类对象的引用名称
1. 设置值
* void set(Object obj, Object value)
2. 获取值
* get(Object obj)
3. 忽略访问权限修饰符的安全检查
* setAccessible(true):暴力反射
* Constructor:构造方法
* 创建对象:
* T newInstance(Object... initargs)
* 如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法
* Method:方法对象
// Object obj :Method对象所在类对象的引用名称
* 执行方法:
* Object invoke(Object obj, Object... args)
* 获取方法名称:
* String getName:获取方法名
总结:
类<?>... parameterTypes:比如String.class(多个)
Object obj :对象的引用,即实例名称
Object... args :实参(多个)
3.框架灵魂
* 需求:写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法(以后只需改配置文件即可)
* 实现:
1. 定义实体类
2. 配置文件xxx.properties
3. 定义框架类
* 步骤:
1. 将需要创建的对象的全类名和该类下要执行的方法定义在配置文件中
2. 在框架类中加载读取配置文件
3. 在框架类中使用反射技术来加载类文件进内存,即获取Class
4. 同上…
Eclipse中Outline里各种图标的含义
先说颜色:
蓝色:no modifier【注】Modifier 类提供了 static 方法(reutrn boolean)和常量
再说形状:
再说字母:
S:static
F:final
A: Abstrct
常用组合:
绿圆圈:public
黄菱形:protected
蓝三角:no modifier
红方块:private
MVC&SpringMVC
MVC:
SpringMvc:
DispatcherServlet(前端控制器名)
SpringMVC思想
Spring MVC 通过一套 MVC 注解,让 POJO成为处理请求的控制器,而无须实现任何接口
POJO:"即简单普通Java对象"区别于EJB
请求转发与重定向
请求转发:
重定向:
REST
答出这两点就够了:
rest其实是基于HTTP的,四种方式
而且每种资源对应特定的URI,资源标识
jsp:
<%
pageContext.setAttribute("ctp", request.getContextPath());
%>
项目路径ctp /order请求随便起名字emp/${id}
Controller:
@RequestMapping(value = "/emp/{id}", method = RequestMethod.GET)
public String getEmp(@PathVariable("id") Integer id, Model model) {…}
但是默认只有get/post两种方式,怎么配置其他两种方式呢?
从页面发起PUT、DELETE形式的请求?Spring提供了对Rest风格的支持
1)、<!-- 支持Rest风格转换的filter -->去web.xml配置这个filter;
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2)、如何发其他形式请求?
按照以下要求;
1、创建一个post类型的表单
2、表单项中携带一个_method的参数
3、这个_method的值就是DELETE、PUT
示例:
<form action="book/1" method="post">
<input name="_method" value="put"/>
<input type="submit" value="更新1号图书"/>
</form>
<form action="book/1" method="post">
<input name="_method" value="put"/>
<input type="submit" value="更新1号图书"/>
</form>
请求处理
1.
@RequestParam
@RequestHeader
@CookieValue
在处理方法入参处使用 @RequestParam 可以把请求参数传递给请求方法
@RequestParam(value = "user", required = false, defaultValue = "你没带") String username,参数二, 参数三
value():指定要获取的参数的key注意这个key是从表单中获取的,则这个key应该写成name对应的值
<input type="hidden" name="id" value="${employee.id }"/>
required():这个参数是否必须的
defaultValue():默认值
…
2. 传入POJO-SpringMVC自动封装
传啥新建啥bean
框架乱码
提交的数据可能有乱码:
* 请求乱码:
* GET请求:改server.xml;在8080端口处URIEncoding="UTF-8"
* POST请求:
* 在第一次获取请求参数之前设置
* 自己写一个filter;而SpringMVC有这个filter
* 相当于request.setCharacterEncoding("UTF-8");
*
* 响应乱码:
* response.setContentType("text/html;charset=utf-8")
所以:
<!-- 使用SpringMVC前端控制器写完就直接写字符编码过滤器;
Tomcat一装上,上手就是server.xml的8080处添加URIEncoding="UTF-8"
-->
<!-- 配置一个字符编码的Filter;一定注意:字符编码filter一般都在其他Filter之前; -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- encoding:指定解决POST请求乱码 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<!-- forceEncoding:顺手解决响应乱码 response.setCharacterEncoding(this.encoding); -->
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
数据传出
/**
* SpringMVC除过在方法上传入原生的request和session外还能怎么样把数据带给页面
*
* 四大域:
* pageContext:${pageScope.msg }<br/>
reqest:${requestScope.msg }<br/>
session:${sessionScope.msg }-${sessionScope.haha}<br/>
application:${applicationScope.msg }<br/>
需要知道一点SpringMVC在调用方法前会创建一个隐含的数据模型,作为模型数据的存储容器, 成为"隐含模型"。也就是说在每一次的前后台请求的时候会随带这一个背包,不管你用没有,这个背包确实是存在的,用来盛放我们请求交互传递的值;
*
* 1)、可以在方法处传入Map、或者Model或者ModelMap。
* 给这些参数里面保存的所有数据都会放在请求域中。可以在页面获取reqest:${requestScope.msg }<br/>
* 关系:
* Map,Model,ModelMap:最终都是BindingAwareModelMap在工作;
* 相当于给BindingAwareModelMap中保存的东西都会被放在请求域中;
*
* Map(interface(jdk)) Model(interface(spring))
* || //
* LinkedHashMap(实现类class) //
* || //
* ModelMap(class) //
* \\ //
* \\ //
* ExtendedModelMap(实现类class)
* |
* ||
* BindingAwareModelMap(class)
ExtendedModelMap:
Model(org.springframework.ui.Model)
Model是一个接口,包含addAttribute方法,其实现类是ExtendedModelMap。
ExtendedModelMap继承了ModelMap类,ModelMap类实现了Map接口。
如下:
*
* 2)、方法的返回值可以变为ModelAndView类型;
* 既包含视图信息(页面地址)也包含模型数据(给页面带的数据);
* 而且数据同样是放在请求域中;
* request、session、application;
*
* 3)、SpringMVC提供了一种可以临时给Session域中保存数据的方式;
* 使用一个注解 @SessionAttributes(只能标在类上)
* @SessionAttributes(value="msg"):
* 给BindingAwareModelMap中保存的数据,或者ModelAndView中的数据,
* 的同时给session中放一份;
* value指定保存数据时要给session中放的数据的key;
*
* value={"msg"}:只要保存的是这种key的数据,给Session中放一份
* types={String.class}:只要保存的是这种类型的数据,给Session中也放一份
*
* 后来推荐@SessionAttributes就别用了,可能会引发异常;
* 给session中放数据请使用原生API;
视图解析
1、请求处理方法执行完成后,最终返回一个 ModelAndView 对象。对于那些返回 String,View 或 ModeMap 等类型的处理方法,Spring MVC 也会在内部将它们装配成一个 ModelAndView 对象,它包含了逻辑名和模型对象(数据model)的视图
2、Spring MVC 借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是 JSP ,也可能是 Excel、JFreeChart 等各种表现形式的视图
3、应用
1)一个ViewResolver接口:
实现类InternalResourceViewResolver:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
return "success";
视图解析器进行拼串来到WebContent/WEB-INF/pages/hello.jsp
2)单独解析不走上面的解析器,不拼串:
return "forward:/hello.jsp";
return "redirect:/hello.jsp";
/代表与WebContent平级的hello.jsp
请求链接的转发和重定向操作,配置的默认视图解析器就不会进行拼串;而是单独解析
3)mvc开挂模式
springDispatcherServlet-servlet.xml下配置
path="/toLoginPage"是index.jsp里的请求链接名
view-name="login"指定指定pages下的返回界面仍然采用自动拼串
,或者写view-name=" forward:/WEB-INF/pages/login.jsp 指定pages下的返回界面
<mvc:view-controller path="/toLoginPage" view-name="login"/>
<!-- 开启mvc注解驱动模式;开启了mvc的开挂模式 -->
<mvc:annotation-driven></mvc:annotation-driven>
这种方式在Controlller中不用写任何代码
RestfulCRUD
利用SpringMVC做一个CRUD(增删改查)符合Rest风格的;
C:Create:创建
R:Retrieve:查询
U:Update:更新
D:Delete:删除
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
添加俩包,支持jstl标签(Java server pages standarded tag library,即JSP标准标签库)
1.效果
员工列表
员工添加:
员工修改
员工删除-点击完成删除来到列表页面
增删改查的URL地址; /资源名/资源标识
/emp/1 GET:查询id为1的员工
/emp/1 PUT:更新id为1的员工
/emp/1 DELETE:删除id为1的员工
/emp POST:新增员工;
/emps GET:查询所有员工
2.流程
1.员工列表展示;
查询所有员工----员工列表展示:访问index.jsp----直接发送/emps到控制器<jsp:forward page="/emps"></jsp:forward>------控制器查询所有员工------放在请求域中(数据传出)-----转发到list页面展示
2.员工添加:
界面1点击添加链接--控制器加model—返回界面2添加界面点击提交—控制器取model直接传参就能取
在list页面点击""员工添加""----控制器(查询出所有的部门信息要展示在页面)----来到添加页面(add.jsp)--------输入员工数据--------点击保存(/emp )------处理器收到员工保存请求(保存员工)--------保存完成以后还是来到列表页面;
spring表单标签:
原来我们全部通过${}取数据
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
使用spring通过 SpringMVC 的表单标签可以实现将模型数据中的属性和 HTML 表单元素相绑定,以实现表单数据更便捷编辑和表单值的回显
新标签里的属性:
path:
1)、当做原生的name项
2)、自动回显隐含模型中某个对象对应的这个属性的值
value:内部值
遍历出的对象的属性,但我们不用像之前去写遍历的标签</c:forEach>
itemLabel: 看到的名字
itemValue:内部值
特色:
1)、SpringMVC认为,表单数据中的每一项最终都是要回显的;(即返回界面会自动渲染请求域中的数据)
path指定的是一个属性;这个属性是从隐含模型(model)(请求域中取出的某个对象中的属性);path指定的每一个属性,请求域中保存的对象一定要拥有这个属性;这个对象就是请求域中的command作为key
2)、modelAttribute="":
可以告诉SpringMVC不要去找command的值了,我放了一个modelAttribute指定自定义的值;比如employee找对象用的key就用employee;
model.addAttribute("employee", new Employee());
3.员工修改
流程同上
需求上在修改页面不加员工名字,那么从页面传回控制器的model对象employee的名字字段就为空,所以要在正式更新之前调用一下被@ModelAttribute标注的方法,该方法根据页面中存的隐藏id查一遍employee,返回employee
隐藏属性:<input type="hidden" name="id" value="${employee.id }"/>
@ModelAttribute :被该注解修饰的方法,会在每一次请求时优先执行,用于接收前台jsp页面传入的参数
4.员工删除
与添加、修改不同的是,删除操作只过一边程序:即只走一遍Controller
引入jQuery.js出404分析
<!-- 默认前端控制器是拦截所有资源(除过jsp),js文件就404了;要js文件的请求是应该交给tomcat处理的
<!-- 告诉SpringMVC,自己映射的请求就自己处理,不能处理的请求(这里的jquery.js引入)直接交给tomcat -->
加标签:
<!-- 这个标签允许静态资源能访问,但动态映射的请求就不行了(比如/emp这种常写的),有副作用 -->
<mvc:default-servlet-handler/>
再加标签
<!-- springmvc可以保证动态请求和静态请求都能访问 -->
<mvc:annotation-driven></mvc:annotation-driven>
SpringMVC源码
1.DispathcherServlet结构分析
1)、所有请求过来DispatcherServlet收到请求,
2)、调用doDispatch()方法进行处理
1)、getHandler():根据当前请求地址找到能处理这个请求的目标处理器类(处理器)
根据当前请求在HandlerMapping中找到这个请求的映射信息,获取到目标处理器类
2)、getHandlerAdapter():根据当前处理器类获取到能执行这个处理器方法的适配器;
根据当前处理器类,找到当前类的HandlerAdapter(适配器)
3)、使用刚才获取到的适配器(AnnotationMethodHandlerAdapter )执行目标方法handler;
4)、目标方法执行后会返回一个ModelAndView对象
5)、根据ModelAndView的信息转发到具体的页面,并可以在请求域中取出ModelAndView中的模型数据
2.HandlerMapping保存请求映射信息
1)、getHandler()会返回目标处理器类的执行链
mappedHandler=getHandle(processedRequest)返回mappedHandler对象即处理器执行链(包含handler目标处理器类,包含interceptor拦截器)
2)、getHandler()细节:怎么根据当前请求就能找到哪个类能来处理?
HandlerMapping:处理器映射:他里面保存了每一个处理器能处理哪些请求的映射信息
handlerMap:ioc容器启动创建Controller对象的时候扫描每个处理器都能处理什么请求,保存在HandlerMapping的handlerMap属性中;下一次请求过来,就来看哪个HandlerMapping中有这个请求映射信息就行了;
3.HandlerAdapter处理目标方法
根据目标处理器类的执行链,找到handler,进一步找到与handler对相应的HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
AnnotationMethodHandlerAdapter:能解析注解方法的适配器;
处理器类中只要有标了注解的这些方法就能用;
annotation-driven
1、只要请求不好使就召唤mvc:annotation-driven;
1)、<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
现象:
1)、都没配?动态资源(@RequestMapping映射的资源能访问,静态资源(.html,.js,.img))
HandlerMapping:
动态能访问:
DefaultAnnotationHandlerMapping中的handlerMap中保存了每一个资源的映射信息;
静态不能访问:
就是handlerMap中没有保存静态资源映射的请求,
HandlerAdapter:九大组件之方法执行的适配器;与HandlerMapping平行
2)、只加一个<mvc:default-servlet-handler/>静态资源ok,动态资源完蛋
HandlerMapping中 变化;
/**org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler即交给tomcat
动态不能访问:DefaultAnnotationHandlerMapping没有了;用SimpleUrlHandlerMapping替换了,他的作咏就是将所有请求直接交给tomcat;如果这个tomcat写了Servlet还好,但这个tuomcat除了配置一个前端控制器以外,别的什么也没配;所以就不能处理动态请求
静态能访问的原因:SimpleUrlHandlerMapping把所有请求都映射给tomcat;
HandlerAdapter:
AnnotationMethodHandlerAdapter都没有了;
3)都加上<mvc:default-servlet-handler/>
<mvc:annotation-driven/>才都能访问
HandlerMapping变化
与前面现象相比,handlerMapping里面多了一个现在有三个,按照从上到下的顺序依次查询,BeanNameUrlHandlerMapping一直没用
多的那一个叫RequestMappingHandlerMapping:动态资源可以访问
多的这一个里面不再有handlerMap,而是handlerMethods
续
SimpleUrlHandlerMapping:将请求直接交给tomcat;有他,静态资源就没问题;
HandlerAdapter:
原来的
AnnotationMethodHandlerAdapter;被换成RequestMappingHandlerAdapter;
RequestMappingHandlerAdapter源码确定参数都用成解析器了
SpringMVC支持Ajax
ajax;
1、原生javaWeb:不再用
1)、导入GSON;
2)、返回的数据用GSON转成json
3)、写出去;
2、SpringMVC快速的完成ajax功能?
导包
jackson-annotations-2.1.5.jar
jackson-core-2.1.5.jar
jackson-databind-2.1.5.jar
无论是请求体还是响应体都是站在服务器端来说的,
只不过
@响应体写在上方
@请求体写在参数位置
3. @ResponseBody响应体
1)、在Controller中写
//@ResponseBody响应体是jackson包提供的
用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端
写在上方
@ResponseBody
@RequestMapping("/getallajax")
public Collection<Employee> ajaxGetAll(){
Collection<Employee> all = employeeDao.getAll();
return all;
}
返回数据all就是json就ok;
2)、在页面中写,$.ajax();
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%
pageContext.setAttribute("ctp", request.getContextPath());
%>
<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
</head>
<body>
<!--%=new Date() %验证默认行为已被禁止-->
<%=new Date() %>
<a href="${ctp }/getallajax">ajax获取所有员工</a><br/>
<div>
</div>
<!--return false;禁用默认行为-->
<script type="text/javascript">
$("a:first").click(function(){
//1、发送ajax获取所有员工上
$.ajax({
url:"${ctp}/getallajax",
type:"GET",
success:function(data){
//console.log(data);
$.each(data,function(){
var empInfo = this.lastName+"-->"+this.birth+"--->"+this.gender;
$("div").append(empInfo+"<br/>");
});
}
});
return false;
});
</script>
</body>
</html>
4、@RequestBody请求体
注意请求体只有form表单才有,而对于链接来说不使用
1)、在Controller中写
@RequestBody String body是基本用法
另外可以封装对象@RequestBody Employee employee是高级用法
@requestBody接收的是前端传过来的json字符串
写在参数位置
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody Employee employee){
System.out.println("请求体:"+employee);
return "success";
}
2)、在页面中写,$.ajax();//js对象(object)转json(string)
<%@ 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>
<%
pageContext.setAttribute("ctp", request.getContextPath());
%>
</head>
<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
<body>
<form action="${ctp }/test02" method="post"
enctype="multipart/form-data">
<input name="username" value="tomcat" /> <input name="password"
value="123456"> <input type="file" name="file" /> <input
type="submit" />
</form>
<a href="${ctp }/testRequestBody">ajax发送json数据</a>
</body>
<script type="text/javascript">
$("a:first").click(function() {
//点击发送ajax请求,请求带的数据是json
var emp = {
lastName : "张三",
email : "[email protected]",
gender : 0
};
//alert(typeof emp);
//js对象(object)转json(string)
var empStr = JSON.stringify(emp);
//alert(typeof empStr);
$.ajax({
url : '${ctp}/testRequestBody',
type : "POST",
data : empStr,
contentType : "application/json",
success : function(data) {
alert(data);
}
});
return false;
});
</script>
</html>
4.1 @RequestParam
后端不以表单形式从前端获取值
5、@HttpEntity参数(怪异)
1)、在Controller中写
与@RequestBody请求体对应
@HttpEntity更强大,不光有请求体,还能获取请求头
@RequestMapping("/test02")
public String test02(HttpEntity<String> str){
System.out.println(str);
return "success";
}
2)、在页面中写;
同样是form表单
<form action="${ctp }/test02" method="post"
enctype="multipart/form-data">
<input name="username" value="tomcat" /> <input name="password"
value="123456"> <input type="file" name="file" /> <input
type="submit" />
</form>
6.ResponseEntity返回值(怪异)
定制相应头
/**
* 将返回数据放在响应体中
*
* ResponseEntity<String>:响应体中内容的类型
* @return
*/
//@ResponseBody
@RequestMapping("/haha")
public ResponseEntity<String> hahah(){
MultiValueMap<String, String> headers = new HttpHeaders();
String body = "<h1>success</h1>";
headers.add("Set-Cookie", "username=hahahaha");
return new ResponseEntity<String>(body , headers, HttpStatus.OK);
}
SpringMVC九大组件
SpringMVC中的Servlet一共有三个层次,分别是HttpServletBean、FrameworkServlet和 DispatcherServlet。
HttpServletBean直接继承自java的HttpServlet,其作用是将Servlet中配置的参数设置到相应的属性;
FrameworkServlet初始化了WebApplicationContext,
DispatcherServlet初始化了自身的9个组件(平行而非嵌套);对9个组件做个概览。
共同点:九大组件全部都是接口;接口就是规范;提供了非常强大的扩展性;
全局Context.this
在学习9个组件之前,我们需要先了解Handler的概念,也就是处理器。它直接应对着MVC中的C也就是Controller层,它的具体表现形式有很多,可以是类,也可以是方法。在Controller层中@RequestMapping标注的所有方法都可以看成是一个Handler,只要可以实际处理请求就可以是Handler。
Handler的概念清楚了,下面开始对9个组件一一介绍。
【1. HandlerMapping】
是用来查找Handler的。在SpringMVC中会有很多请求,每个请求都需要一个Handler处理,具体接收到一个请求之后使用哪个Handler进行处理呢?这就是HandlerMapping需要做的事。
【2. HandlerAdapter】
从名字上看,它就是一个适配器。因为SpringMVC中的Handler可以是任意的形式,只要能处理请求就ok,但是Servlet需要的处理方法的结构却是固定的,都是以request和response为参数的方法。如何让固定的Servlet处理方法调用灵活的Handler来进行处理呢?这就是HandlerAdapter要做的事情。
小结:Handler是用来干活的工具;HandlerMapping用于根据需要干的活找到相应的工具;HandlerAdapter是使用工具干活的人。
【3. HandlerExceptionResolver】
其它组件都是用来干活的。在干活的过程中难免会出现问题,出问题后怎么办呢?这就需要有一个专门的角色对异常情况进行处理,在SpringMVC中就是HandlerExceptionResolver。具体来说,此组件的作用是根据异常设置ModelAndView,之后再交给render方法进行渲染。
【4. ViewResolver】
ViewResolver用来将String类型的视图名和Locale解析为View类型的视图。View是用来渲染页面的,也就是将程序返回的参数填入模板里,生成html(也可能是其它类型)文件。这里就有两个关键问题:使用哪个模板?用什么技术(规则)填入参数?这其实是ViewResolver主要要做的工作,ViewResolver需要找到渲染所用的模板和所用的技术(也就是视图的类型)进行渲染,具体的渲染过程则交由不同的视图自己完成。
【5. RequestToViewNameTranslator】
ViewName是根据ViewName查找View,但有的Handler处理完后并没有设置View也没有设置ViewName,这时就需要从request获取ViewName了,如何从request中获取ViewName就是RequestToViewNameTranslator要做的事情了。RequestToViewNameTranslator在Spring MVC容器里只可以配置一个,所以所有request到ViewName的转换规则都要在一个Translator里面全部实现。
【6. LocaleResolver】
解析视图需要两个参数:一是视图名,另一个是Locale。视图名是处理器返回的,Locale是从哪里来的?这就是LocaleResolver要做的事情。LocaleResolver用于从request解析出Locale,Locale就是zh-cn之类,表示一个区域,有了这个就可以对不同区域的用户显示不同的结果。SpringMVC主要有两个地方用到了Locale:一是ViewResolver视图解析的时候;二是用到国际化资源或者主题的时候。
【7. ThemeResolver】
用于解析主题。SpringMVC中一个主题对应一个properties文件,里面存放着跟当前主题相关的所有资源、如图片、css样式等。SpringMVC的主题也支持国际化,同一个主题不同区域也可以显示不同的风格。SpringMVC中跟主题相关的类有 ThemeResolver、ThemeSource和Theme。主题是通过一系列资源来具体体现的,要得到一个主题的资源,首先要得到资源的名称,这是ThemeResolver的工作。然后通过主题名称找到对应的主题(可以理解为一个配置)文件,这是ThemeSource的工作。最后从主题中获取资源就可以了。
【8. MultipartResolver】
用于处理上传请求。处理方法是将普通的request包装成MultipartHttpServletRequest,后者可以直接调用getFile方法获取File,如果上传多个文件,还可以调用getFileMap得到FileName->File结构的Map。此组件中一共有三个方法,作用分别是判断是不是上传请求,将request包装成MultipartHttpServletRequest、处理完后清理上传过程中产生的临时资源。
【9. FlashMapManager】
用来管理FlashMap的,FlashMap主要用在redirect中传递参数。
【总结】
至此,SpringMVC中的9大组件也就简单地概述了一遍。通过对此9大组件的宏观认识,对分析SpringMVC的设计、原理与实现都会有很大的帮助作用。
springmvc.xml标配
<context:component-scan base-package="com.atguigu"></context:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<mvc:default-servlet-handler/>
<mvc:annotation-driven ></mvc:annotation-driven>
文件上传
小贴士,eclipse中复制一份已有的项目
1.copy,改名
2.右键---properties----web Project Settings—更改访问路径Context root写入新的文件名
1.单个文件上传
1)jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<%
pageContext.setAttribute("ctp", request.getContextPath());
%>
</head>
<body>
<!--
文件上传
1.写表单;:enctype="multipart/form-data"
2.导入fileuplod包
commons-fileupload-1.2.1.jar
commons-io-2.0.jar
3.javaweb.......
3.现在用框架
只需要在springmvc配置文件中,编写一个文件上传解析器MultiPartResolver九大组件之一
4.文件上传请求处理写Controller
-->
<!-- action最好写全路径 -->
${msg }
<!-- 取一下model保存的提示信息 -->
<form action="${ctp }/upload" method="post" enctype="multipart/form-data">
用户头像:<input type="file" name="headerimg"/><br/>
用户名:<input type="text" name="username"/><br/>
<input type="submit"/>
</form>
</body>
</html>
2)springmvc.xml
编写一个文件上传解析器MultiPartResolver九大组件之一,其余配置都是标配
<context:component-scan base-package="com.atguigu"></context:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 配置文件上传解析器MultiPartResolver接口,用CommonsMultipartResolver实现类
id必须是multipartResolver
-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="#{1024*1024*20}"></property>
<property name="defaultEncoding" value="UTF-8"></property>
</bean>
<mvc:default-servlet-handler/>
<mvc:annotation-driven ></mvc:annotation-driven>
3)Controller
@Controller
public class FileUploadController {
@RequestMapping("/upload")
public String upload(@RequestParam(value="username",required = false)String username,
@RequestParam("headerimg")MultipartFile file,
Model model) {
System.out.println("上传文件的信息");
System.out.println("文件的名字:"+file.getName());//假名(jsp文件项的<name="">)
System.out.println("文件的名字:"+file.getOriginalFilename());//真名
//文件保存
try {
file.transferTo(new File("G:\\"+file.getOriginalFilename()));
model.addAttribute("msg","文件上传成功了");
} catch (Exception e) {
// TODO Auto-generated catch block
model.addAttribute("msg","文件上传失败了"+e.getMessage());
}
//懒得再写新的jsp了
return "forward:/index.jsp";
}
}
2.多个文件上传
1)jsp里多谢几个<input type="file" name="headerimg"/><br/>
2)Controller
@Controller
public class FileUploadController {
@RequestMapping("/upload")
public String upload(@RequestParam(value="username",required = false)String username,
@RequestParam("headerimg")MultipartFile[] file,
Model model) {
对MultipartFile[] file增强型for循环
同上
//懒得再写新的jsp了
return "forward:/index.jsp";
}
}
拦截器
SpringMVC提供了拦截器机制;允许运行目标方法之前进行一些拦截工作,或者目标方法运行之后进行一些其他处理;
Filter;javaWeb
HandlerInterceptor:SpringMVC
preHandle:在目标方法运行之前调用;返回boolean;return true;(chain.doFilter())放行; return false;不放行
postHandle:在目标方法运行之后调用:目标方法调用之后
afterCompletion:在请求整个完成之后;来到目标页面(或者是报错页面)之后;
1)、正常写控制器类,拦截器类与控制器类分开写
2)、拦截器是一个接口,实现HandlerInterceptor接口;
3)、springmvc.xml配置拦截器
4)、拦截器的运行流程
1、单个拦截器
正常运行流程;
拦截器的preHandle----目标方法---拦截器postHandle---目标页面---拦截器的afterCompletion;
MyFirstInterceptor...preHandle...
test01....
MyFirstInterceptor...postHandle...
success.jsp....
MyFirstInterceptor...afterCompletion
其他流程:
1、只要preHandle不放行(return false)就没有以后的流程;
2、只要preHandle放行了,不管目标方法handler炸不炸,afterCompletion总是都会执行;
2、多个拦截器
正常流程:
Af-----------------------Bf-------------------------
先进后出,后进先出
MyFirstInterceptor...preHandle...
MySecondInterceptor...preHandle...
test01....
MySecondInterceptor...postHandle...
MyFirstInterceptor...postHandle...
success.jsp....
MySecondInterceptor...afterCompletion...
MyFirstInterceptor...afterCompletion
异常流程:
1、不放行;
1)、哪一块不放行从此以后都没有;
但是MySecondInterceptor不放行;但是他前面已经放行了的拦截器的afterCompletion总会执行;
MyFirstInterceptor...preHandle...
MySecondInterceptor...preHandle...
MyFirstInterceptor...afterCompletion
3.总结
拦截器的preHandle:是按照顺序执行(放行)
拦截器的postHandle:是按照逆序执行
拦截器的afterCompletion:是按照逆序执行;
已经放行了的拦截器的afterCompletion总会执行;
SpringMVC运行流程:
1、所有请求,前端控制器(DispatcherServlet)收到请求,调用doDispatch进行处理
2、根据HandlerMapping中保存的请求映射信息找到,处理当前请求的,处理器执行链(包含拦截器interceptor)
getHandle(processedRequest);返回mappedHandler对象即处理器执行链(包含拦截器)
3、根据当前处理器找到他的HandlerAdapter(适配器)
4、拦截器的preHandle先执行
5、适配器执行目标方法,并返回ModelAndView
1)、ModelAttribute注解标注的方法提前运行
2)、执行目标方法的时候(确定目标方法用的参数)
1)、有注解比如@RequestParam()
2)、没注解:
1)、 看是否Model、Map以及其他的,
这种情况是往model对象里加东西存留于请求域中
2)、如果是自定义类型
1)、从隐含模型中看有没有,如果有就从隐含模型中拿
2)、如果没有,再看是否SessionAttributes标注的属性,如果是从Session中拿,如果拿不到会抛异常
3)、都不是,就利用反射创建对象
6、拦截器的postHandle执行
7、处理结果;(页面渲染流程)
1)、如果有异常使用异常解析器处理异常;处理完后还会返回ModelAndView
2)、调用render进行页面渲染
1)、视图解析器根据视图名得到视图对象
2)、视图对象调用render方法;
3)、执行拦截器的afterCompletion;
SS整合
SpringMVC和Spring整合的目的;分工明确;
SpringMVC的配置文件就来配置和网站转发逻辑以及网站功能有关的(视图解析器,文件上传解析器,支持ajax,xxx);springmvc.xml
Spring的配置文件来配置和业务有关的(事务控制,数据源,xxx);spring.xml
1. <import resource="spring.xml"/>:可以合并配置文件;虽然是两个spring配置文件,但这种方式仍然相当于一个ioc
2.规范整合
分容器,即两个ioc
1)、在web.xml已经配置SpringMVC的基础上,添加spring容器到web.xml
注意:我们之前配置spring到xml那是一个java项目,并没有web.xml
<!-- needed for ContextLoaderListener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
2)、防止两个容器中的组件(只要加注解的组件会被容器创建),被重复创建
SpringMVC.xml与Spring.xml分别加代码
因为Spring管理业务逻辑组件;
排除扫描Controller组件
<context:component-scan base-package="com.atguigu">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
因为SpringMVC管理控制器组件;
只扫描Controller组件 要禁用默认行为
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
3)、注意子父容器问题
Spring是一个父容器,SpringMVC是一个子容器;
子容器还可以引用父容器的组件;
父容器不能引用子容器的组件;
注意调用方式,按正常的调用方式即可Controller调Service