服务器端三层架构:表现层(SpringMVC)、业务层(Spring)、持久层(Mybatis)
表现层:拿到http请求的参数,传递给spring
SpringMVC:一种基于Java实现的MVC设计模型的请求驱动类型的轻量级框架
M(model):javaBean对象(将参数封装成JavaBean对象交给业务层处理)
V(view):jsp (向控制器提交数据,显示模型中的数据)
C(controller):servlet(根据视图提出的请求判断将请求交给那个模型处理,将处理后的结果交给对应的视图更新显示)
在Spring MVC框架中,从“Request(请求)”开始,依次进入“DispatcherServlet(核心分发器)” —> “HandlerMapping(处理器映射)” —> “Controller(控制器)” —> “ModelAndView(模型和视图)” —> “ViewResolver(视图解析器)” —> “View(视图)” —> “Response(响应)”结束,其中DispatcherServlet、HandlerMapping和ViewResolver 只需要在XML文件中配置即可,从而大大提高了开发的效率,特别是对于 HandlerMapping 框架为其提供了默认的配置。
1.HandlerMapping(处理器映射):通过映射找到哪个控制器执行哪个方法@RequestMapping(path=“”)再通过HandlerAdapter适配器执行方法
2.ViewResolver(视图解析器):找到哪个视图的显示
SpringMVC和struct2区别:
(1)共同:都是表现层框架,离不开ServletAPI, 请求的机制都是一个核心控制器
(2)不同:1.SpringMVC核心控制器是Servlet,Struct是Filter
2.SpringMVC是基于方法设计的,Struct是基于类设计的,前者效率较高
3.SpringMVC使用更简洁,支持JSR303,处理ajax请求更方便
4.Struct的OGNL表达式比SpringMVC开发效率高,执行效率比JSTL低,尤其Struct的表单标签,没有html效率高
mvc:annotation-driven/打开注解(处理器映射器、处理器适配器、视图解析器配置)
使用maven构建webapp项目,maven添加archetypeCatalog=internal,国外服务器太慢
RequestMapping:可用在类和方法上
@RequestMapping(path = “/start”,method = RequestMethod.GET,params = {“username”})
params指的是必须携带的参数 username=?
请求参数绑定
当你以表当post提交参数时,RequestMapping可以根据HandlerMapping寻找指定controller携带的javabean类对象参数将参数封装成一个bean对象返回(jsp表单指定属性name值要与bean对象属性名相同,当参数时包装对象时,应使用包装对象里的对象名加属性)
<form action="params/userVoadd" method="post">
username<input type="text" name="user.username"></br>
password<input type="password" name="user.password"></br>
money<input type="text" name="user.money"></br>
UserVoName<input type="text" name="userVoname"></br>
UserVoPassword<input type="text" name="userVopassword"></br>
<input type="submit" value="submit">
</form>
请求时参数转换器
(1)首先定义一个类继承Converter或者formatter类,
前者可用泛型表达参数转换类型<String,Integer>,后者使用,formatter转换源类型必须是String,对于Web应用Http发送的数据都是以String类型存储,使用formatter更合适
public class Convertors implements Converter<String,Date> {
@Override
public Date convert(String s) {
if(s==null){
throw new RuntimeException("请你传入数据!");
}
DateFormat df=new SimpleDateFormat("yyyy-MM-dd");
try {
return df.parse(s);
} catch (ParseException e) {
throw new RuntimeException("转换出错");
}
}
}
(2)在主文件中配置装换器
<bean class="org.springframework.context.support.ConversionServiceFactoryBean" id="conversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.dingxiang.utils.DateConvertor.Convertors"/>
</set>
</property>
</bean>
(3)在注解中打开转换器
<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"/>
常用注解
(1)RequestParam=request.getParameter(“name”)(name和value属性基本等同,required表示是否必须)
用s来获取参数username
public String testRequestParam(@RequestParam(name = "username")String s){
System.out.println(s);
return "start";
}
(2)RequestBody(获取请求体的内容,得到key=value&keyvalue…,gei方式不适用)
获取表单传递参数,用字符串接受
public String testRequestBody(@RequestBody String body){
System.out.println(body);
return "start";
}
(3)PathVariable使用RESTful风格,即根据参数传递类型和参数数量选取不同的方法执行,
使用占位符{}直接传入参数
@RequestMapping("/testPathVariable/{id}")
public String testPathVariable(@PathVariable(value = "id") String body){
System.out.println(body);
return "start";
}
使用静态方法发送请求 浏览器插件测试各种请求方式
(4) RequestHeader(少用)
@RequestHeader(value = "User-Agent")
(5)CookieValue(少用)
@CookieValue(value = "JSESSIONID")
(6)ModelAttribute(方法、参数)首先执行
用于将多个参数封装到一个实体对象,从而简化数据绑定流程,自动暴露为模型数据,在视图展示时使用
两种方法,返回bean对象或者通过把bean对象加入到集合使用注解来读取
@RequestMapping("/testModelAttribute")
public String testModelAttribute(@ModelAttribute("1") User user){
System.out.println("testModelAttribute");
System.out.println(user.toString());
return "start";
}
@ModelAttribute
public void modelattribute(Map<String,User> map){
User user=new User();
user.setDate(new Date());
user.setMoney(12.212);
map.put("1",user);
}
@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user){
System.out.println("testModelAttribute");
System.out.println(user.toString());
return "start";
}
@ModelAttribute
public User modelattribute(){
User user=new User();
user.setDate(new Date());
user.setMoney(12.212);
return user;
}
(7)SessionAttribute
使用HttpSession的话需要servletAPI支持,存在耦合
value代表我们需要把什么样的对象放入session
@SessionAttributes(value = {"name"})
(8)不让前端控制器拦截资源文件
<mvc:resources mapping="/css/**" location="/css/**"/>
(9)ResponseBody 使用到了json转换器jackson,添加maven依赖
核心包:jackson-databind jackson-annatation jackson-core
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.1</version>
</dependency>
jQuery Ajax实现前后台json数据传输并使用@RequestBody封装成对象传输到后台@ResponseBody封装成对象返回到jsp
$(function () {
$('#ajax').click(function () {
$.ajax({
url:'user/testAjax2',
contentType:'application/json; charset=UTF-8',
type:'post',
data:'{"username":"zoufuob","password":"12345"}',
dataType:'json',
error:function () {
alert("获取数据失败")
},
success:function (data) {
alert(data.username)
alert(data.password)
}
})
})
})
//jackson把json String封装发哦user对象
@RequestMapping("/testAjax2")
public @ResponseBody User testAjax2(@RequestBody User user){
System.out.println("执行了testAjax2");
System.out.println(user);
//模拟查找修改数据库数据
user.setUsername("wangdatao");
user.setPassword("52zoufubo");
return user;
}
异常处理
(1)异常类 继承Exception
(2)异常解析类 实现接口HandlerExceptionResolver重写resolveException方法
public ModelAndView resolveException(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o, Exception e) {
//获取异常对象
SysException exception=null;
if(e instanceof SysException){
exception= (SysException) e;
}else{
exception = new SysException("error");
}
//创建modelandview
ModelAndView modelAndView=new ModelAndView();
modelAndView.addObject("errorMsg",exception.getMsg());
modelAndView.setViewName("error");
return modelAndView;
}
(3)配置异常处理器(配置异常解析类对象到spring)
文件上传
表单 enctype=“multipart/form-data”
1.文件上传
用MultipartFile对象作为Controller参数接收表单传入数据,通过transferTo方法上传文件
public String testUpload2(HttpServletRequest request, MultipartFile upload2)throws Exception{
System.out.println("文件上传");
String path=request.getSession().getServletContext().getRealPath("/uploads/");
File file=new File(path);
if(!file.exists()){
file.mkdir();
}
String name=upload2.getOriginalFilename();
String uuid=UUID.randomUUID().toString().replace("-","");
name=uuid+"_"+name;
upload2.transferTo(new File(path,name));
return "success";
}
2.跨服务器上传文件
(1)创建客户端对象
(2)与服务器建立连接
(3)传入数据
@RequestMapping("testUpload3")
public String testUpload3(MultipartFile upload3) throws IOException {
System.out.println("跨服务器文件上传");
String path="http://localhost:8090/uploads/";
String name=upload3.getOriginalFilename();
String uuid=UUID.randomUUID().toString().replace("-","");
name=uuid+"_"+name;
//创建客户端对象
Client client=Client.create();
//与服务器进行连接
WebResource resource=client.resource(path+name);
//传文件
resource.put(upload3.getBytes());
return "success";
}
拦截器
功能与过滤器基本相同,但是拦截器只能对用户请求的方法进行拦截,用在权限验证,判断用户是否登录,记录请求信息的日志
(1)拦截器类 实现接口HandlerInterceptor 可重写
preHandle(返回true时执行下一个拦截器,没有拦截器时执行Controller)
postHandle(该方法在控制器请求方法调用之后,视图解析之前进行执行)
afterHandle(在视图解析后执行)
(2)配置拦截器
<mvc:interceptors>
<mvc:interceptor>
<!--要拦截的方法-->
<mvc:mapping path="/user/testInterceptor"/>
<bean class="com.dingxiang.Interceptor.MyInterceptor" id="myInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<!--要拦截的方法-->
<mvc:mapping path="/user/testInterceptor"/>
<bean class="com.dingxiang.Interceptor.MyInterceptor2" id="myInterceptor2"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/login/main"/>
<bean class="com.dingxiang.Interceptor.loginInterceptor.LoginInterceptor" id="loginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
数据验证
网页前端验证后还需要在服务器端对数据进行验证
1.Spring Validator接口
首先需要编写一个Vaidator类实现该接口,对数据进行验证的配置,相当于JSR303的注解配置验证信息;
然后再主配置文件中配置一个ReloadableResourceBundleMessageSource Bean并打开注解validator
<bean class="org.springframework.context.support.ReloadableResourceBundleMessageSource" id="messageSource">
<property name="basename" value="classpath:errorMessege"/>
</bean>
<mvc:annotation-driven validator="validator"/>
2.JSR303 JSR-303 是 Java EE 6 中的一项子规范,叫做 Bean Validation JSR 303 用于对 Java Bean 中的字段的值进行验证。
-
Bean Validation 中内置的 constraint
@Null
被注释的元素必须为 null
@NotNull
被注释的元素必须不为 null
@AssertTrue
被注释的元素必须为 true
@AssertFalse
被注释的元素必须为 false
@Min(value)
被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)
被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)
被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value)
被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min)
被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction)
被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past
被注释的元素必须是一个过去的日期
@Future
被注释的元素必须是一个将来的日期
@Pattern(value)
被注释的元素必须符合指定的正则表达式 -
Hibernate Validator 附加的 constraint
@Email
被注释的元素必须是电子邮箱地址
@Length
被注释的字符串的大小必须在指定的范围内
@NotEmpty
被注释的字符串的必须非空
@Range
被注释的元素必须在合适的范围内
与Validator不同的是需要配置一个LocalValidatorFactoryBean
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
<property name="validationMessageSource" ref="messageSource"/>
</bean>