springmvc框架

SpringMvc框架简介

Spring MVC属于SpringFrameWork的后续产品。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的SpringMVC框架或集成其他MVC开发框架,如Struts1,Struts2等。

SpringMvc框架结构

这里写图片描述

Spring MVC开发结构

package com.baobaotao.web;

@Controller         ① 将UserController变成一个Handler
@RequestMapping(“/user”)     ②指定控制器映射的URL
public class UserController {

    @RequestMapping(value = “/register”) ③处理方法对应的URL,相对于
                                                                                    ②处的URL
    public String register() {
              return “user/register”; ④返回逻辑视图名
    }
}

@RequestMapping Rest风格Url

REST是设计风格而不是标准 目的只是让url看起来更简洁实用,是资源状态的一种表达,资源是由URI来指定,对资源的操作包括获取、创建、修改和删除资源这些操作正好对应HTTP协议提供的GET、POST、PUT和DELETE方法。通过操作资源的表现形式来操作资源。
常用操作:
GET 获取
POST 提交
PUT 更新
Delete 删除
常用的url风格例如:
http://blog.csdn.net/liaomin416100569/article/details/53212754

web.xml
<!-- springmvc配置 -->
    <servlet>
        <servlet-name>mvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc</servlet-name>
        <url-pattern>/</url-pattern>  拦截所有的路径
    </servlet-mapping>

通过请求方法限定:模拟请求方法

通过在web.xml中配置一个org.springframework.web.filter.HiddenHttpMethodFilter
通过POST请求的_method参数指定请求方法,HiddenHttpMethodFilter动态更改HTTP头信息。

<!-- 请求method支持put和delete必须添加过滤器-->
    <filter>
        <filter-name>myFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>myFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

过滤器解决乱码(web.xml)

    <!-- 解决乱码的配置 -->
    <filter>
        <filter-name>Filter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

要支持put和delete动作必须要在form表单中加隐藏表单域
value=”提交方式”

<form action="${pageContext.request.contextPath}/user/2" method="post">
        <input type='hidden' name="_method" value="delete">
        <input type="text" name="name"/>
        <input type="submit" value="提交"/>
    </form>

通过请求方法限定:代码示例

示例1@RequestMapping(value=“/delete”) 
public String test1(@RequestParam("userId") String userId){
    return "user/test1";            
} 所有URL为<controllerURI>/delete的请求由test1处理(任何请求方法)


示例2@RequestMapping(value="/delete",method=RequestMethod.POST) 
public String test1(@RequestParam("userId") String userId){
    return "user/test1";            
} 所有URL为<controllerURI>/delete 且请求方法为POST 的请求由test1处理

文件上传和下载

使用springMVC包装的解析器(CommonsMultipartResolver)进行文件上传控制 需要引入 apache的 common-fileupload组件包

pom.xml

<!-- 文件上传 -->
<dependency>
     <groupId>commons-fileupload</groupId>
     <artifactId>commons-fileupload</artifactId>
      <version>1.3.3</version>
</dependency>
  1:设置表单属性
      <form action="<%=path %>/fileUpload.htm" method="post" enctype="multipart/form-data">
        文件  <input type="file" name="myImg"/> 
     </form>
   2:springmvc配置文件中添加文件解析器:
      <!-- (启动文件上传) 名称必须使用  multipartResolver 因为spring容器使用名称注入 文件上传解析器-->
    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 限制文件上传大小 -->
        <property name="maxUploadSize" value="5242880"></property>
    </bean>

   3:  action方法接受文件 
  @RequestMapping(value="food",method=RequestMethod.POST)
    public String addFood(String foodName, String price,MultipartFile imageUrl,Model model){
        //获取文件名
        String fileName="/"+imageUrl.getOriginalFilename();
        //获取绝对路径
        String absPath="E:\\数据库\\5.JSP&SRV\\教学软件\\apache-tomcat-6.0.45\\webapps\\SpringMvcDay\\image";
        try {
            imageUrl.transferTo(new File(absPath+"\\"+fileName));
            service.saveFood(foodName, price, fileName);
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {

            e.printStackTrace();
        }
        return queryFoodAll(foodName, 1, model);或(suc.jsp)
    }

下载
SpringMVC使用消息转换器 ByteArrayHttpMessageConverter 设置文件内容为响应体 通过设置响应头ContentDisposition 通知浏览器下载的附件名称

@RequestMapping(value="/download",method=RequestMethod.GET)
    public ResponseEntity<byte[]>  downFood(String imagePath) throws IOException{
        String absPath="E:\\数据库\\5.JSP&SRV\\教学软件\\apache-tomcat-6.0.45\\webapps\\SpringMvcDay\\image"+imagePath;

        String fileName=imagePath;
           //需要下载的目标文件
           File file=new File(absPath);
           //设置响应头
           HttpHeaders hh=new HttpHeaders();
           //设置下载的文件的名称
           hh.setContentDispositionFormData("attachment", URLEncoder.encode(fileName, "UTF-8"));
           //读取目标文件为二进制数组
           byte[] fileByte=FileCopyUtils.copyToByteArray(file);
           //构建ResponseEntity对象
           ResponseEntity<byte[]> re=new ResponseEntity<byte[]>(fileByte, hh, HttpStatus.CREATED);
           return re;

    }

由于ConversionService在进行类型转换时,可以使用到Bean所在宿主类的上下文信息(包括类结构,注解信息),所以可以实施更加高级的类型转换,如注解驱动的格式化等功能。

@RequestMapping("/aa")
public String userRegister(@RequestParam("user") User user){
    return “forward:/suc.jsp”;
}
以上User类,通过一个@RequestParam注解,将参数user 转换为 User对象类型

数据校验框架

Spring 的DataBinder在进行数据绑定时,可同时调用校验框架完成数据校验工作。在Spring MVC中,则可直接通过注解驱动的方式进行数据校验。
Spring的org.springframework.validation是校验框架所在的包

pom.xml

<!-- jsr303验证 框架-->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>4.3.2.Final</version>
    </dependency>

JSR 303
JSR 303通过在Bean属性上标注类似于@NotNull、@Max等标准的注解指定校验规则,并通过标准的验证接口对Bean进行验证。
你可以通过http://jcp.org/en/jsr/detail?id=303了解JSR 303的详细内容。
这里写图片描述

数据校验框架
会默认装配好一个LocalValidatorFactoryBean,通过在处理方法的入参上标注@Valid注解即可让Spring MVC在完成数据绑定后执行数据校验的工作。

public class UserInfo { 
    /**
     * NotNull 属性名!=null
     * NotEmpty 属性名!=null && !属性名.equals("")
     */
    @NotEmpty(message="用户名不能为空")
    private String userName;//用户名

    @NotEmpty(message="密码不能为空")
    private String password;//密码

    @NotEmpty(message="再次输入密码不能为空")
    private String repassword;//确认密码

    //xxx@126.com 
    @Pattern(message="邮箱格式错误",regexp=".+@.+\\..+")

    private String email;//邮件

    @NotEmpty(message="年龄不能为空")
    @Min(value=1,message="年龄必须大于1")
    @Max(value=100,message="年龄必须小于100")
    private String age;//年龄

    @Size(min=11,max=11,message="手机号码必须是11位")
    private String phone;//手机号码

    @NotEmpty(message="网址不能为空")
    @Pattern(message="网址格式错误",regexp="(http://|ftp://|https://|www){0,1}[^\u4e00-\u9fa5\\s]*?\\.(com|net|cn|me|tw|fr)[^\u4e00-\u9fa5\\s]*")
    private String net;//个人网址

    @Past(message="日期格式不正确,必须是一个过去的日期")
    @DateTimeFormat(pattern="yyyy-MM-dd")
    private Date dates;//日期
    }

注意:Spring本身没有提供JSR 303的实现,所以必须将JSR 303的实现者(如Hibernate Validator)的jar文件放到类路径下,Spring将自动加载并装配好JSR 303的实现者。

如何使用注解驱动的校验

@ModelAttribute(“user”) 控制bean的名字

@RequestMapping(value="/regs",method=RequestMethod.POST)
    public String regist(@ModelAttribute("user") @Valid UserInfo user,BindingResult errors){
        if(!user.getPassword().equals(user.getRepassword())){
            errors.addError(new FieldError("user", "password", "两次输入密码不一致"));
        }
        if(errors.hasErrors()){
            return "/lesson03/reg.jsp";
        }
        return "/lesson03/suc.jsp";

    }

在已经标注了JSR 303注解的表单/命令对象前标注一个@Valid,Spring MVC框架在将请求数据绑定到该入参对象后,就会调用校验框架根据注解声明的校验规则实施校验。

Spring MVC是通过对处理方法签名的规约来保存校验结果的:前一个表单/命令对象的校验结果保存在其后的入参中,这个保存校验结果的入参必须是BindingResult或Errors类型,这两个类都位于org.springframework.validation包中。

校验错误信息存放在什么地方??

这里写图片描述
4.Spring MVC将HttpServletRequest对象数据绑定到处理方法的入参对象中(表单/命令对象);
5.将绑定错误信息、检验错误信息都保存到隐含模型中;
6.本次请求的对应隐含模型数据存放到HttpServletRequest的属性列表中,暴露给视图对象。

页面如何显示错误信息

要引用标签库(jsp页面中)
<%@ taglib prefix=”form” uri=”http://www.springframework.org/tags/form” %>

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c"      uri="http://java.sun.com/jsp/jstl/core" %>   
<%@ taglib prefix="form"   uri="http://www.springframework.org/tags/form" %>
<html>
<head>
<title>注册用户</title>
  <style>.errorClass{color:red}</style>
</head>
<body> 

        <form action="<%=path %>/regs" method="post" > 
            用户名:<input type="text"  name="userName"/>
             <!-- <form:errors path="对象名.字段名">-->
            <font color="red"><form:errors path="user.userName"></form:errors></font>
            <br/><br/>

            密码  :<input type="password"  name="password"/>
            <font color="red"><form:errors path="user.password"></form:errors></font>
            <br/><br/>
            确认密码:<input type="password" name="repassword"/>
            <font color="red"><form:errors path="user.repassword"></form:errors></font>
            <br/><br/>
            邮件:<input type="text" name="email"/>
            <font color="red"><form:errors path="user.email"></form:errors></font>
            <br/><br/>
            年龄:<input type="text" name="age"/>
            <font color="red"><form:errors path="user.age"></form:errors></font>
            <br/><br/>
            手机号码:<input type="text" name="phone"/>
            <font color="red"><form:errors path="user.phone"></form:errors></font>
            <br/><br/>
            个人网址:<input type="text" name="net"/>
            <font color="red"><form:errors path="user.net"></form:errors></font>
            <br/><br/>
            日期 :<input type="text" name="dates"/>
            <font color="red"><form:errors path="user.dates"></form:errors></font>
            <br/><br/>
                <input type="button" value="注册" onclick="checkSubmit()"/><br/>
        </form>
</body>
</html>

数据模型访问结构

这里写图片描述

访问数据模型:ModelAndView

通过ModelAndView

第一种
@RequestMapping(value="/case2",method=RequestMethod.GET)
    public ModelAndView case2( ){
        ModelAndView mav=new ModelAndView("/lesson03/test.jsp");
        mav.setViewName("/lesson03/test.jsp");
        return mav;
    }
第二种
@RequestMapping(value="/case2",method=RequestMethod.GET)
    public ModelAndView case2( ){
        ModelAndView mav=new ModelAndView();
        mav.setViewName("/lesson03/test.jsp");
        mav.addObject("sex", "男");
        return mav;
    }
两者相同

访问数据模型:@ModelAttribute

springmvc中Model相关对象 的处理和数据相关的对象
 @ModelAttribute 重命名 参数数据
 Model 传递数据到视图(request.setAttribute)
 ModelMap 传递数据到视图
 Map传递数据到视图
 ModelAndView 绑定数据到视图。(ModelMap

1.使用方式一
@ModelAttribute 重命名 参数数据

@RequestMapping(value = "/handle61")
public String  handle61(@ModelAttribute("user") User user){
    user.setUserId("1000");
    return "/lesson03/test.jsp";
}

2.使用方式二

访问UserController中任何一个请求处理方法前,Spring MVC先执行该方法,并将返回值以user为键添加到模型中
@ModelAttribute("user")
public User getUser(){            
    User user = new User();   
    user.setUserId("1001"); 
    return user;
}
在此,模型数据会赋给User的入参,然后再根据HTTP请求消息进一步填充覆盖user对象
@RequestMapping(value = "/handle62")
public String  handle62(@ModelAttribute("user") User user){
    user.setUserName("tom");
    return "/user/showUser";
}

访问数据模型:@SessionAttributes

如果希望在多个请求之间共用某个模型属性数据,则可以在控制器类标注一个@SessionAttributes,Spring MVC会将模型中对应的属性暂存到HttpSession中:

@Controller
public class SessionController {

    @ModelAttribute("user")
    public User getUser(){
        User user=new User();
        return user;
    }

    /**
     * http://localhost:8080/SpringMvcDay/s1?id=1
     * 请求重定向(两次请求)redirect: 使用SessionAttributes用于在重定向中传值将值存在session中用完记住清除
     * @SessionAttributes("要共享的模型对象")共享数据
     */
    @RequestMapping(value="/s1",method=RequestMethod.GET)
    public String case1(@ModelAttribute("user") User user ){
        return "redirect:/s2";
    }
    @RequestMapping(value="/s2",method=RequestMethod.GET)
    public String case2(String id ,Map map,HttpServletResponse response,SessionStatus status) throws IOException{
        User user= (User)map.get("user");
        response.getWriter().println(user.getId());
        //关闭session
        status.setComplete();
        return null;
    }
}
@Controller
public class SessionController {
    /**
     * http://localhost:8080/SpringMvcDay/s1?id=1
     * 请求转发(默认 请求方式不改变   一次请求)forward:
     */
    @RequestMapping(value="/s1",method=RequestMethod.GET)
    public String case1(Map map ){
        //模型层的数据不可共享
        map.put("age", 15);
        return "forward:/s2";

    }
    @RequestMapping(value="/s2",method=RequestMethod.GET)
    public String case2(String id ,HttpServletResponse response) throws IOException{
        response.getWriter().println(id);
        return null;
    }
}

Spring MVC如何解析视图

这里写图片描述

mvc-servlet.xml

<!-- 视图解析器的配置 -->
    <bean id="resourceViewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/"></property>  前缀
    <property name="suffix"value=".jsp"></property> 后缀
 </bean>

例子

@Controller
public class ViewController {
    @RequestMapping(value="/viewResover",method=RequestMethod.GET)
    public String view(){
        return "lesson04/result";
    }
}

本地化:(国际化)基础原理

spring.xml

<!-- 国际化配置  注意messageSource必须是bean的名称 -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="com/et/lesson04/resource/my"></property>
    </bean>
mvc-servlet.xml


    <!-- 该拦截器用于url上的参数 国际化 
        只是当jsp经过action之后才会将当前的国际和语言存储在session中 同时从session中获取
    -->
    <mvc:interceptors>
        <bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
            <property name="paramName" value="a"></property>
        </bean>
    </mvc:interceptors>

<!-- 国际化时   参数需被临时存储的地方 当用户再次访问时应该使用之前的参数 -->
    <bean id="localeResolver"
    class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
    </bean> 

name=”paramName” 表示获取参数 value=”a” 默认名字是Locale

mvc-servlet.xml

    <!-- 验证本身不支持国际化自定义验证 从新指定验证bean validator="localValidatorFactoryBean"-->
    <bean id="localValidatorFactoryBean" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <property name="validationMessageSource" ref="messageSource" ></property>
    </bean>

    <!-- springmvc配置拦截/ 所有的资源都被拦截(图片无法展示)将除控制台以外的资源交会给servlet处理 -->
    <mvc:default-servlet-handler />
    <!-- 将springmvc注解的action交给springmvc处理 -->
    <mvc:annotation-driven  validator="localValidatorFactoryBean"></mvc:annotation-driven>

将错误信息国际化 validator=”localValidatorFactoryBean”验证控制层数据

配置国际化资源文件:my_en_US.properties
my_zh-CN.properties

在form表单中如何应用国际化要应用标签库:
这里写图片描述

显示消息:<t:message code="键">

例子:http://localhost:9080/user/handle91?locale=en_US

/**
 * 国际化
 * @author Administrator
 *
 */
@Controller
public class NationController {
    //自动装配MessageSource
    @Autowired
    MessageSource ms;
    @RequestMapping(value="/nation",method=RequestMethod.GET)
    public String tes(HttpServletResponse response,OutputStream os,Locale locale) throws NoSuchMessageException, IOException{
        response.setContentType("text/html;charset=UTF-8");
        os.write(ms.getMessage("key", null, locale).getBytes("UTF-8"));
        return null;
    }

    /**
     * 中转
     * @return
     */
    @RequestMapping(value="/mid",method=RequestMethod.GET)
    public String mid(){
        return "/lesson04/reg.jsp";
    }

    @RequestMapping(value="/myregs",method=RequestMethod.POST)
    public String regist(@ModelAttribute("user") @Valid UserInfo user,BindingResult errors){
        if(!user.getPassword().equals(user.getRepassword())){
            errors.addError(new FieldError("user", "password", "两次输入密码不一致"));
        }
        if(errors.hasErrors()){
            return "/lesson04/reg.jsp";
        }
        return "/lesson04/suc.jsp";
    }
}
reg.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://www.springframework.org/tags/form"  prefix="form"%>
<%@taglib uri="http://www.springframework.org/tags"  prefix="t"%>

<html>
  <head>
    <title>国际化</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->
    <script type="text/javascript">
        function checkSubmit(){
            document.forms[0].submit();
        }
    </script>
  </head>

  <body>
        <a href="${pageContext.request.contextPath}/mid?a=zh_CN">中文</a>&nbsp;<a href="${pageContext.request.contextPath}/mid?a=en_US">English</a>
        <form action="${pageContext.request.contextPath}/myregs" method="post" > 
            <t:message code="userName"></t:message>:<input type="text"  name="userName"/>
            <font color="red"><form:errors path="user.userName"></form:errors></font>
            <br/><br/>
            <t:message code="password"></t:message><input type="password"  name="password"/>
            <font color="red"><form:errors path="user.password"></form:errors></font>
            <br/><br/>
            <t:message code="repassWord"></t:message>:<input type="password" name="repassword"/>
            <font color="red"><form:errors path="user.repassword"></form:errors></font>
            <br/><br/>
            <t:message code="email"></t:message><input type="text" name="email"/>
            <font color="red"><form:errors path="user.email"></form:errors></font>
            <br/><br/>
            <t:message code="age"></t:message><input type="text" name="age"/>
            <font color="red"><form:errors path="user.age"></form:errors></font>
            <br/><br/>
            <t:message code="phone"></t:message>:<input type="text" name="phone"/>
            <font color="red"><form:errors path="user.phone"></form:errors></font>
            <br/><br/>
            <t:message code="net"></t:message>:<input type="text" name="net"/>
            <font color="red"><form:errors path="user.net"></form:errors></font>
            <br/><br/>
            <t:message code="dates"></t:message><input type="text" name="dates"/>
            <font color="red"><form:errors path="user.dates"></form:errors></font>
            <br/><br/>
                <input type="button" value="<t:message code="zhu"></t:message>" onclick="checkSubmit()"/><br/>
        </form>
  </body>
</html>

静态资源处理

Spring MVC 3.0提供的最强大的功能之一!!!
1.静态资源处理方式
2.静态资源映射

静态资源处理:原理

这里写图片描述

静态资源处理:如何配置?

第一步:web.xml让所有请求都由Spring MVC处理

<servlet>
    <servlet-name>springServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

物理静态资源路径映射逻辑资源路径

<mvc:resources mapping="/resources/**" 
                           location="/"/

这里写图片描述

**location必须是存在的物理路径 /表示上下文根路径
mapping表示映射的地址 **表示目录下所有的文件及子文件
假设 存在WEB-INF/img/test.png 由于安全问题 WEB-INF是
无法直接访问 设置以下映射**

<mvc:resources mapping="/img/**"  location="/WEB-INF/images/"/>

直接通过地址: http://localhost:8080/上下文路径/img/test.png访问
注意:spring4.2: servlet3.0(Javaee6)支持
spring4.0: servlet2.5(Javaee5)支持

过滤器和拦截器的区别

拦截器是类似于过滤器的一中机制springmvc是使用servlet实现的中央处理器Dispatcherservlet有实现自己的过滤器,拦截springmvc的action 必须实现接口 HandlerInterceptor
这里写图片描述

public class MyInteractor implements HandlerInterceptor {

    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
    }

    public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
    }
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        return false;
    }
}

false表示不通过 true通过

自定义拦截器

mvc-servlet.xml

    <!-- 该拦截器用于url上的参数 国际化 
        只是当jsp经过action之后才会将当前的国际和语言存储在session中 同时从session中获取
    -->
    <mvc:interceptors>
        <bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
            <property name="paramName" value="a"></property>
        </bean>
        <!-- 自定义拦截器 -->
        <mvc:interceptor>
            <!-- 要拦截的action  path="/**"拦截所有的 -->
            <mvc:mapping path="/inter"/>
            <bean class="com.et.lesson05.MyInteractor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

防止重复提交

1、产生token,并存在session中
2、随机页面生成
3、提交页面与session进行比对,成功后对session进行销毁
4、第二次提交则不存在这个值而报错
1)由于服务器响应缓慢,用户刷新提交POST请求造成的重复提交。

 2)用户点击后退按钮,返回到数据提交界面,导致的数据重复提交。

 3)用户多次点击提交按钮,导致的数据重复提交。

 4)用户恶意避开客户端预防多次提交手段,进行重复数据提交。
这里写图片描述

自定义标签放入WEB-INF目录下(tags文件)
要应用<%@ tag%>指令
这里写图片描述

token.tag

<%@ tag language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@attribute name="tokenName"  required="false" %>
<!-- 自定义属性
    ranStr:随机值
    required="false" 是否时必填项
-->
<%
    String ranStr=UUID.randomUUID().toString();
    String key=(tokenName==null?"myToken":tokenName);
    session.setAttribute(key,ranStr);
 %>
<input type='hidden' name='<%=key %>' value='<%=ranStr %>'/>
money.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib tagdir="/WEB-INF/tags" prefix="my" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>防止重复提交</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>
  <body>
    <form action="${pageContext.request.contextPath }/tm">&nbsp; 
        扣款:<input name="money">
            <!--应用自定义标签 -->
            <my:token></my:token>
        <input name="提交" type="submit">
    </form>
  </body>
</html>
@Controller
public class MoneyController {
    /**
     * 扣钱
     * @return
     * @throws IOException
     */
    @Autowired
    MoneyDaoImpl mdi;
    @RequestMapping(value="/tm",method=RequestMethod.GET)
    public String reg(Integer money,OutputStream os,HttpServletResponse response) throws IOException{
        response.setContentType("text/html;charset=UTF-8");
        mdi.trasnateMoney(money);
        os.write(("剩余的钱为 :"+mdi.selectMoney()).getBytes("UTF-8"));
        return null;
    }
}
/**
 * 拦截器必须实现接口HandlerInterceptor
 * 防止重复提交
 */
public class TokenInteractor implements HandlerInterceptor {

    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
    }

    public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
    }
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        //获取参数myToken
        String myToken=request.getParameter("myToken");
        //从session中获取myToken
        Object myToken1=request.getSession().getAttribute("myToken");
        //需要验证重复提交
        if(myToken!=null){
            //重复提交
            if(myToken1==null){
                return false;
            }else{
                if(myToken.equals(myToken1)){//第一次提交
                    //成功之后清除session中myToken
                    request.getSession().removeAttribute("myToken");
                    return true;
                }else {
                    return false;
                }
            }
        }else{
            return true;
        }
    }
}

AJAX原理

Ajax概念
Ajax 是Web 开发一个流行的词汇,全称 Asynchronous JavaScript and XML,异步的JavaScript和XML 。是几种技术的强强联合。
Ajax如何工作
Ajax(即异步 JavaScript 和 XML)是一种 Web 应用程序开发的手段,它采用客户端脚本与 Web 服务器交换数据。
为什么要学习Ajax
使用Ajax的最大优点,就是能在不更新整个页面的前提下维护数据。这使得Web应用程序更为迅捷地回应用户动作,并避免了在网络上发送那些没有改变过的信息

Ajax交互流程

这里写图片描述

XMLHttpRequest对象简介

XMLHttpRequest对象是整个Ajax开发的基础
提供客户端和服务器异步通信的能力
能够向服务器发出请求
能够接收服务器的返回页面
最早出现在IE,随着应用的广泛,渐渐推广到其他浏览器中
为了应对所有的现代浏览器,包括 IE5 和 IE6,请检查浏览器是否支持 XMLHttpRequest 对象。如果支持,则创建 XMLHttpRequest 对象。如果不支持,则创建 ActiveXObject

var xmlhttp;
if (window.XMLHttpRequest)
  {// code for IE7+, Firefox, Chrome, Opera, Safari
  xmlhttp=new XMLHttpRequest();
  }
else
  {// code for IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }

发送请求

这里写图片描述

回调 onreadystatechange 事件

不需要调用的匿名函数叫回调函数(当请求发送后收到结果后会自动调用该方法)
这里写图片描述

什么是Json

JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
JSON 是轻量级的文本数据交换格式
JSON 独立于语言 *
JSON 具有自我描述性,更易理解
* JSON 使用 JavaScript 语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。
总结JSON的特点
(1)在客户端(特指PC浏览器),直接使用JavaScript语言解析JSON,无需第三方jar包
(2)本质上,就是一个文本,只是该文本有特定的书写格式
(3)可以使用第三方工具,将JavaBean对象或者List/Set/Map对象转成JSON
(4)优点:JSON与XML很相似,但是它更加轻巧,服务器只需发送一个html普通字符串,不用发送复杂的xml格式文档了
(5)缺点:语法过于严谨,初学者可能觉得代码不易读,写错一点都不行
(6)JSON本质上,就是用JS语法写的特殊文本记号,用JS可以直接解析**

例子:

{  
    "name":"张三", 属性:值
    "url":"http://www.baidu.com",
    "address":[{
        "street":"观澜",
        "city": "深圳",
        "country":"中国",
    },{
        "street":"观澜",
        "city": "深圳",
        "country":"中国",
    }]
}

{
    "employees": [
        { "firstName":"Bill" , "lastName":"Gates" },
        { "firstName":"George" , "lastName":"Bush" },
        { "firstName":"Thomas" , "lastName":"Carter" }
    ]
}

数据库中JSON表的格式

//表示一行
{
   id1,
   name:"A"
}

//两行就是数组
[
    {
      id1,
      name:"A"
    },
    {
      id2,
      name:"B"
    }
]

javaScript中JSON的格式

<script>
    var a={
        id:1,
        name:'张三',
        address:[
            {city:'深圳',street:'观澜'},
            {city:'兰州',street:'大富路'}
        ]
    }
    //alert(a.name);
    //alert(a.address[1].street);
    //alert(a.address.length);

    //字符串
    var str='{"id":1,"username":"A"}';
    //错误
    //alert(str.id);
    //转成json
    var obj=JSON.parse(str);
    alert(obj.id);
</script>

用java模拟JSON

public class Address {
    String city="深圳";
    String country="中国";
    String street="观澜";
}

public class UserInfo {
    String name="张三";
    String url="http://www.baidu.com";
    Address address;
}   

模拟的结构为:

    /* JSON中
     * 普通数据   属性:值
     * 键:{
     * 
     * }
     * 
     * 数组
     * 键:[
     * 
     * ]
     * {}代表一个对象   多个对象用[] 数组
     * 
     */
      {  
        "name":"张三", 属性:值
        "url":"http://www.baidu.com",
        "address":[{
            "street":"观澜",
            "city": "深圳",
            "country":"中国",
        },{
            "street":"观澜",
            "city": "深圳",
            "country":"中国",
        }]
    }

回顾传统Web应用请求和响应特点【显示当前时间】

(1)请求:浏览器以HTTP协议的方式提交请求到服务器
(2)响应:服务器以HTTP协议的方式响应内容到浏览器
注意:HTTP是WEB大众化非安全协议
HTTPS是WEB安全协议,是基于HTTP协议的,且加了一些加密等特殊功能,常用于在线支付,或者是需要安全性较高的网站中,例如:12306网站
HTTP请求有三个部份组成:请求行,请求头,请求体
HTTP响应有三个部份组成:响应行,响应头,响应体
(3)状态栏:有明显的进度条刷新现象,如果服务器响应较慢的话,进度条刷新也会变慢,IE9等中高版本浏览器,有明显转圈圈图标
(4)历史栏:会收集原来已访问过的web页面,进行缓存
(5)缺点:不需变化的大量数据,也全部刷新,造成浏览器加载和处理负担
(6)可改进的地方:让不需变化的大量数据,原封不动,不用缓存到历史栏中,无需全部刷新,只刷新某些需要变化的数据区域,例如:当前时间的区域
AJAX开发步骤
步一:创建AJAX异步对象,例如:createAJAX()
步二:准备发送异步请求,例如:ajax.open(method,url)
步三:如果是POST请求的话,一定要设置AJAX请求头,例如:ajax.setRequestHeader()
如果是GET请求的话,无需设置设置AJAX请求头
步四:真正发送请求体中的数据到服务器,例如:ajax.send()
步五:AJAX不断的监听服务端响应的状态变化,例如:ajax.onreadystatechange,后面写一个无名处理函数
步六:在无名处理函数中,获取AJAX的数据后,按照DOM规则,用JS语言来操作Web页面

当前时间:<span>${requestScope.str}</span><br/>
    <input type="button" value="同步方式提交"/>
    <script type="text/javascript">
        //定位button按钮,同时添加单击事件
        document.getElementsByTagName("input")[0].onclick = function(){
            var url = "${pageContext.request.contextPath}/TimeServlet?id="+new Date().getTime();
            window.location.href = url; 
        }
    </script>

将java对象转成JSON必须依赖jar包 Json-lib

pom.xml

    <!-- json的配置-->
    <dependency>
      <groupId>net.sf.json-lib</groupId>
      <artifactId>json-lib</artifactId>
      <version>2.4</version>
      <classifier>jdk15</classifier>
    </dependency>
/**
 * 模拟数据库
 * @author Administrator
 *
 */
public class Test {

    /**
     * map转成json对象
     * 结果:{"id":1,"username":"A"}
     * @param args
     */
    public static void parseObject(){
        //一个map一行数据
        Map map=new HashMap();
        map.put("id", 1);
        map.put("username", "A");
        JSONObject jo=JSONObject.fromObject(map);
        System.out.println(jo.toString());
    }

    /**
     * 集合转成json
     * json字符串的键必须带" " 例:"key":1 值如果是数字可以不带 字符串必须带
     * 结果:[{"id":1,"username":"A"},{"id":2,"username":"B"}]
     * @param args
     */
    public static void parseArray(){
        //一个map一行数据
        Map map=new HashMap();
        map.put("id", 1);
        map.put("username", "A");

        Map map1=new HashMap();
        map1.put("id", 2);
        map1.put("username", "B");

        List list=new ArrayList();
        list.add(map);
        list.add(map1);
        JSONArray ja=JSONArray.fromObject(list);
        System.out.println(ja.toString());
    }
    /**
     * 多层嵌套
     * {  
        "name":"张三", 属性:值
        "url":"http://www.baidu.com",
        "address":{
            "street":"观澜",
            "city": "深圳",
            "country":"中国",
        }
     */
    public static void parseJsonArray(){
        //一个map一行数据
        Map map=new HashMap();
        map.put("id", 1);
        map.put("username", "A");

        Map  address=new HashMap();
        address.put("city", "深圳");
        address.put("country","中国");
        map.put("addss", address);


        JSONObject jo=JSONObject.fromObject(map);
        System.out.println(jo.toString());
    }

    public static void main(String[] args) {

        //parseObject();
        //parseArray();
        parseJsonArray();
    }
}

使用ajax和springmvc完成增删改查例子:

@Repository
public class MyFoodDaoImpl {
    @Autowired
    JdbcTemplate jdbc;
    public List<Map<String, Object>> queryAllFood(String foodname){
        String sql="select * from food where foodname like '%"+foodname+"%'";
        List<Map<String, Object>> list= jdbc.queryForList(sql);
        return list;
    }
    public void deleteFood(String foodId){
        String sql="delete from food where foodid="+foodId;
        jdbc.execute(sql);

    }

    public void saveFood(String foodName,String price){
        String sql="insert into food(foodid,foodname,price) values((select IFNULL(max(foodid),0)+1 from food f),'"+foodName+"',"+price+")";
        jdbc.execute(sql);
    }
    public void updateFood(String foodId,String foodName,String price){
        String sql="update food set foodname='"+foodName+"',price="+price+" where foodid="+foodId;
        jdbc.execute(sql);
    }
}
/**
     * 查询方法
     * 原始的输出json方式
     * 通过OutputStream os
     * os.write(通过第三方json-lib转换的json字符串.getBytes)
     */
    @Autowired
    MyFoodDaoImpl mdi;
    @RequestMapping(value="/queryAll",method={RequestMethod.GET})
    public String myfood(String foodname,OutputStream os,HttpServletResponse response) throws UnsupportedEncodingException, IOException{
        //response.setContentType("text/html;charset=UTF-8");
        List<Map<String, Object>> queryFood=mdi.queryAllFood(foodname);
        JSONArray arr=JSONArray.fromObject(queryFood);
        //获取json的字符串
        String str=arr.toString();
        os.write(str.getBytes("UTF-8"));
        return null;

    }


    /**
     * 删除方法
     */
    @RequestMapping(value="/food/{foodid}",method=RequestMethod.DELETE)
    public String deleteFood(@PathVariable String foodid,OutputStream os,HttpServletResponse response) throws UnsupportedEncodingException, IOException{
        try {
            mdi.deleteFood(foodid);
            os.write("1".getBytes("UTF-8"));

        } catch (Exception e) {
            os.write("0".getBytes("UTF-8"));
        }
        return null;
    }
    /**
     * 添加方法
     */
    @RequestMapping(value="/food",method={RequestMethod.POST})
    public String saveFood(String foodName,String price,OutputStream os,HttpServletResponse response) throws UnsupportedEncodingException, IOException{
        try {
            mdi.saveFood( foodName, price);
            os.write("1".getBytes("UTF-8"));
        } catch (Exception e) {
            os.write("0".getBytes("UTF-8"));
        }
        return null;
    }
    /**
     * 修改方法
     */
    @RequestMapping(value="/food/{foodid}",method={RequestMethod.PUT})
    public String updateFood(@PathVariable String foodid,String foodName,String price,OutputStream os,HttpServletResponse response) throws UnsupportedEncodingException, IOException{
        try {
            mdi.updateFood(foodid, foodName, price);
            os.write("1".getBytes("UTF-8"));
        } catch (Exception e) {
            os.write("0".getBytes("UTF-8"));
        }
        return null;
    }

}
food.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title>My JSP 'food.jsp' starting page</title>
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
        <script type="text/javascript">
            function query() {
                //调用http://localhost:8080/SpringMvcDay/queryAll 获取数据通过dom方法添加到table中
                //ajax(异步)+json

                var xmlhttp = null;
                //兼容所有的浏览器创建这个对象(简称XHR对象)
                if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
                    xmlhttp = new XMLHttpRequest();
                } else {// code for IE6, IE5
                    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
                }

                //匿名函数  不需要调的函数叫回调函数  当请求发送后回自动调用该方法
                xmlhttp.onreadystatechange = function() {
                    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                        //返回字符串的json
                        var resultJson = xmlhttp.responseText;
                        //转换为js对象
                        var resultObj = JSON.parse(resultJson);
                        //获取table对象
                        var table = document.getElementById("myTable");
                        //将所有名字为dataTr的tr全部删除
                        var allDataTr = document.getElementsByName("dataTr");
                        var length = allDataTr.length;
                        for ( var i = 0; i < length; i++) {
                            table.removeChild(allDataTr[0]);
                        }

                        //根据json的行数追加多个tr
                        for ( var i = 0; i < resultObj.length; i++) {
                            var obj = resultObj[i];
                            //创建<td>
                            var tid = document.createElement("td");
                            //将内容添加到td中
                            tid.innerText = obj.foodid;
                            var tname = document.createElement("td");
                            tname.innerText = obj.foodname;
                            var tprice = document.createElement("td");
                            tprice.innerText = obj.price;
                            //创建<tr>
                            var tr = document.createElement("tr");
                            tr.setAttribute("name", "dataTr");
                            tr.appendChild(tid);
                            tr.appendChild(tname);
                            tr.appendChild(tprice);
                            table.appendChild(tr);
                        }
                    }
                }
                //获取文本框中的名称
                var foodname = document.getElementById("foodName").value;
                //open方法表示产生一个请求的关联(get 提交)
                xmlhttp.open("GET", "${pageContext.request.contextPath}/queryAll?foodname="
                        + foodname, true);
                xmlhttp.send();
            }
    </script>
    </head>
    <body>
        <input type="text" name="foodName" id="foodName">
        <input type="button" value="查询" onclick="query()">
        <table id="myTable" border="1">
            <tr>
                <th>菜品编号</th>
                <th>菜品名</th>
                <th>菜品价格</th>
            </tr>
        </table>
    </body>
</html>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title>My JSP 'food.jsp' starting page</title>
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
        <script type="text/javascript">
        function sendAjax(url,methodType,param,retnFunction){
            //调用http://localhost:8080/SpringMvcDay/queryAll 获取数据通过dom方法添加到table中
                //ajax(异步)+json

                var xmlhttp = null;
                //兼容所有的浏览器创建这个对象(简称XHR对象)
                if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
                    xmlhttp = new XMLHttpRequest();
                } else {// code for IE6, IE5
                    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
                }

                    //匿名函数  不需要调的函数叫回调函数  当请求发送后回自动调用该方法
                xmlhttp.onreadystatechange = function() {
                    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                        retnFunction(xmlhttp.responseText);
                    }
                }
                if(methodType=="get" || methodType=="GET"){
                    //open方法表示产生一个请求的关联(get 提交)
                    xmlhttp.open("GET",url+"?"+param, true);
                    xmlhttp.send();
                }else{
                //open方法表示产生一个请求的关联(POST 提交)
                xmlhttp.open("POST",url, true);
                xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded;charset=UTF-8");
                xmlhttp.send(param);
                }
        }
            function query() {
                var foodname=document.getElementsByName("foodName")[0].value;
                sendAjax("${pageContext.request.contextPath}/queryAll","GET","foodname="+foodname,function(responseText){
                    //返回字符串的json
                var resultJson = responseText;
                //转换为js对象
                var resultObj = JSON.parse(resultJson);
                //获取table对象
                var table = document.getElementById("myTable");
                //将所有名字为dataTr的tr全部删除
                var allDataTr = document.getElementsByName("dataTr");
                var length = allDataTr.length;
                for ( var i = 0; i < length; i++) {
                    table.removeChild(allDataTr[0]);
                }

                //根据json的行数追加多个tr
                for ( var i = 0; i < resultObj.length; i++) {
                    var obj = resultObj[i];
                    //创建<td>
                    var tid = document.createElement("td");
                    //将内容添加到td中
                    tid.innerText = obj.foodid;
                    var tname = document.createElement("td");
                    tname.innerText = obj.foodname;
                    var tprice = document.createElement("td");
                    tprice.innerText = obj.price;
                    var td2=document.createElement("td");
                    //删除按钮
                    var ib=document.createElement("button");
                    ib.innerText="删除";
                    td2.appendChild(ib);
                    //修改按钮
                    var ib1=document.createElement("button");
                    ib1.innerText="修改";
                    td2.appendChild(ib1);
                    //创建<tr>
                    var tr = document.createElement("tr");
                    //将当前对象绑定到当前按钮
                    ib.foodObj=obj;
                    //将当前行的tr绑定当按钮上
                    ib.myLineTr=tr;
                    //删除按钮事件
                    ib.addEventListener("click",function(){
                    //获取按钮
                    var eventStr=event.srcElement;
                    //删除当前行+发送ajax请求到后台删除数据库
                    table.removeChild(eventStr.myLineTr);
                        sendAjax("${pageContext.request.contextPath}/food/"+ib.foodObj.foodid,"POST","_method=delete",function(responseText){
                         if(responseText==1)
                            alert("删除成功");
                         else{
                            alert("删除失败");
                         }
                      });
               });
               //将当前对象绑定到当前按钮
                ib1.foodObj=obj;
               //修改按钮事件
                ib1.addEventListener("click",function(){
                    //获取按钮
                    var eventStr=event.srcElement;
                    document.getElementById('updateDiv').style.display='block';
                    document.getElementsByName("updateFoodName")[0].value=eventStr.foodObj.foodname;
                    document.getElementsByName("updateFoodPrice")[0].value=eventStr.foodObj.price;
                    document.getElementsByName("updateFoodId")[0].value=eventStr.foodObj.foodid;
                });

                    tr.setAttribute("name", "dataTr");
                    tr.appendChild(tid);
                    tr.appendChild(tname);
                    tr.appendChild(tprice);
                    tr.appendChild(td2);
                    table.appendChild(tr);
                }
            });
        }
/**
  新增的方法
*/
function saveFood(){
   var myFoodName=document.getElementsByName("myFoodName")[0].value;
   var myFoodPrice=document.getElementsByName("myFoodPrice")[0].value;
   sendAjax("${pageContext.request.contextPath}/food","POST","foodName="+myFoodName+"&price="+myFoodPrice,function(responseText){
         if(responseText==1){
            document.getElementById('addDiv').style.display='none';
            query();
            alert("新增成功");

         }else{
            alert("新增失败");
         }
    });
}

/**
  修改的方法
*/
function updateFood(){
   var myFoodName=document.getElementsByName("updateFoodName")[0].value;
   var myFoodPrice=document.getElementsByName("updateFoodPrice")[0].value;
   var myFoodId=document.getElementsByName("updateFoodId")[0].value;
   sendAjax("${pageContext.request.contextPath}/food/"+myFoodId,"POST","_method=put&foodName="+myFoodName+"&price="+myFoodPrice,function(responseText){
      if(responseText==1){
            document.getElementById('updateDiv').style.display='none';
            query();
            alert("修改成功");

         }else{
            alert("修改失败");
         }
    });
}
    </script>
    </head>
    <body>
        <input type="text" name="foodName" id="foodName">
        <input type="button" value="查询" onclick="query()">
        <input type="button" value="添加" onclick="document.getElementById('addDiv').style.display='block';">
        <table id="myTable" border="1">
            <tr>
                <th>菜品编号</th>
                <th>菜品名</th>
                <th>菜品价格</th>
                <th>操作</th>
            </tr>
        </table>
    </body>
    <div id="addDiv" style="display:none;position: absolute;left:45%;z-index: 100;border:1px solid black;width: 240px;height: 65px">
        菜品名&nbsp;:<input type="text" name="myFoodName"><br/>
        菜品价格:<input type="text" name="myFoodPrice"><br/>
            <input type="button" value="保存" onclick="saveFood()">&nbsp;<input type="button" value="关闭" onclick="document.getElementById('addDiv').style.display='none';">
    </div>

    <div id="updateDiv" style="display:none;position: absolute;left:45%;z-index: 100;border:1px solid black;width: 240px;height: 90px">
        <input type="hidden" name="updateFoodId"><br/>
        菜品名&nbsp;:<input type="text" name="updateFoodName"><br/>
        菜品价格:<input type="text" name="updateFoodPrice"><br/>
            <input type="button" value="修改" onclick="updateFood()">&nbsp;<input type="button" value="关闭" onclick="document.getElementById('updateDiv').style.display='none';">
    </div>
</html>

返回json的三种方式

/**
     * 查询方法
     * 原始的输出json方式
     * 通过OutputStream os
     * os.write(通过第三方json-lib转换的json字符串.getBytes)
     */
    @Autowired
    MyFoodDaoImpl mdi;
    @RequestMapping(value="/queryAll",method={RequestMethod.GET})
    public String myfood(String foodname,OutputStream os,HttpServletResponse response) throws UnsupportedEncodingException, IOException{
        //response.setContentType("text/html;charset=UTF-8");
        List<Map<String, Object>> queryFood=mdi.queryAllFood(foodname);
        JSONArray arr=JSONArray.fromObject(queryFood);
        //获取json的字符串
        String str=arr.toString();
        os.write(str.getBytes("UTF-8"));
        return null;
    }

    /**
     *第二种直接返回字节数组(byte 默认支持消息转换器) 
     *添加注解@ResponseBody
     *减少流输出的动作 os.write(str.getBytes("UTF-8"));
     */
    @ResponseBody
    @RequestMapping(value="/queryAllReturn",method={RequestMethod.GET})
    public byte[] myfoodReturn(String foodname) throws UnsupportedEncodingException, IOException{
        //response.setContentType("text/html;charset=UTF-8");
        List<Map<String, Object>> queryFood=mdi.queryAllFood(foodname);
        JSONArray arr=JSONArray.fromObject(queryFood);
        //获取json的字符串
        String str=arr.toString();
        return str.getBytes("UTF-8");
    }


/**
     *第三种直接返回对象  springmvc自动转成json(默认是不可以 需要消息转换器(MappingJackson2HttpMessageConverter)
     *会覆盖字节数组的消息转换器所有同时加字节数组的消息转换器ByteArrayHttpMessageConverter)
     *添加注解@ResponseBody
     */
    @ResponseBody
    @RequestMapping(value="/queryAllList",method={RequestMethod.GET})
    public List<Map<String, Object>> foodMap(String foodname) throws UnsupportedEncodingException, IOException{
        List<Map<String, Object>> queryFood=mdi.queryAllFood(foodname);
        return queryFood;

    }
mvc-servlet.xml

<!-- 将springmvc注解的action交给springmvc处理 -->
    <mvc:annotation-driven  validator="localValidatorFactoryBean">
        <mvc:message-converters>
            <!-- 配置返回字节数组解析成json的消息转换器 -->
            <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                    <!-- 设置响应支持的类型 -->
                        <value>text/html;charset="UTF-8"</value>
                        <!-- 设置请求body支持的类型 -->
                        <value>application/x-www-form-urlencoded</value>
                    </list>
                </property>
            </bean>
            <!-- 配置返回对象解析成json的消息转换器 -->
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                    <!-- 设置响应支持的类型 -->
                        <value>text/html;charset="UTF-8"</value>
                        <!-- 设置请求body支持的类型 -->
                        <value>application/x-www-form-urlencoded</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值