SpringMVC_02

二、Rest

2.1 简介

Rest:系统希望以非常简洁的URL地址来发请求;
怎样表示对一个资源的增删改查用请求方式来区分

/getBook?id=1 :查询图书
/deleteBook?id=1:删除1号图书
/updateBook?id=1:更新1号图书
/addBook :添加图书

Rest推荐;
url地址这么起名; /资源名/资源标识符
/book/1 :GET-----查询1号图书
/book/1 :PUT------更新1号图书
/book/1 :DELETE-----删除1号图书
/book :POST-----添加图书
系统的URL地址就这么来设计即可;
简洁的URL提交请求,以请求方式区分对资源操作;
问题:从页面上只能发起两种请求,GET、POST;
其他的请求方式没法使用;

2.2 使用Rest来构建一个增删改查系统

页面地址:
发起图书的增删改查请求;使用Rest风格的URL地址;
请求url 请求方式 表示含义
/book/1 GET: 查询1号图书
/book/1 DELETE:删除1号图书
/book/1 PUT: 更新1号图书
/book POST: 添加1号图书
从页面发起PUT、DELETE形式的请求

处理程序:

package com.atguigu.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class BookController {
    /**
     * 处理查询图书请求
     * @param id
     * @return
     */
    @RequestMapping(value="/book/{bid}",method=RequestMethod.GET)
    public String getBook(@PathVariable("bid")Integer id) {
        System.out.println("查询到了"+id+"号图书");
        return "success";
    }

    /**
     * 图书删除
     * @param id
     * @return
     */
    @RequestMapping(value="/book/{bid}",method=RequestMethod.DELETE)
    public String deleteBook(@PathVariable("bid")Integer id) {
        System.out.println("删除了"+id+"号图书");
        return "success";
    }

    /**
     * 图书更新
     * @return
     */
    @RequestMapping(value="/book/{bid}",method=RequestMethod.PUT)
    public String updateBook(@PathVariable("bid")Integer id) {
        System.out.println("更新了"+id+"号图书");
        return "success";
    }

    @RequestMapping(value="/book",method=RequestMethod.POST)
    public String addBook() {
        System.out.println("添加了新的图书");
        return "success";
    }
}
@Override    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)           
 throws ServletException, IOException {    
  //获取表单上_method带来的值(delete\put)        
  String paramValue = request.getParameter(this.methodParam);         
  //判断如过表单是一个post而且_method有值        
  if ("POST".equals(request.getMethod()) && StringUtils.hasLength(paramValue)) {          
  //转为PUT、DELETE            
  String method = paramValue.toUpperCase(Locale.ENGLISH);          
  //重写了request.getMethod();            
  HttpServletRequest wrapper = new HttpMethodRequestWrapper(request, method);          
  //wrapper.getMethod()===PUT;            
  filterChain.doFilter(wrapper, response);        
  }        
  else {             
  //直接放行            
  filterChain.doFilter(request, response);        
  }   
  }

从页面发起PUT、DELETE形式的请求?Spring提供了对Rest风格的支持
1)、SpringMVC中有一个Filter;他可以把普通的请求转化为规定形式的请求;配置这个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.3 如何发其他形式请求?

按照以下要求;1、创建一个post类型的表单 2、表单项中携带一个_method的参数,3、这个_method的值就是DELETE、PUT

–>

<a href="book/1">查询图书</a><br/>
<form action="book" method="post">
    <input type="submit" value="添加1号图书"/>
</form><br/>
<!-- 发送DELETE请求 -->
<form action="book/1" method="post">
    <input name="_method" value="delete"/>
    <input type="submit" value="删除1号图书"/>
</form><br/>
<!-- 发送PUT请求 -->
<form action="book/1" method="post">
    <input name="_method" value="put"/>
    <input type="submit" value="更新1号图书"/>

</form><br/>

三、请求参数

3.1入参处理

package com.atguigu.controller;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.atguigu.book.Book;

@Controller
public class HelloController {

    /**
     * request.getParameter("").....
     *
     * @return
     */
    @RequestMapping("/hello")
    public String handle01() {
        System.out.println("handle01...");
        return "success";
    }

    /**
     * SpringMVC如何获取请求带来的各种信息 默认方式获取请求参数: 直接给方法入参上写一个和请求参数名相同的变量。这个变量就来接收请求参数的值;
     * 带:有值,没带:null;
     *
     * @RequestParam:获取请求参数的;参数默认是必须带的;
     * @RequestParam("user")String username username =
     *                             request.getParameter("user")
     *
     *
     * @RequestParam("user")
     * @PathVariable("user")
     *                       /book/【{user}pathvariable】?【user=admin(requestparam)
     *                       】
     *
     *                       value:指定要获取的参数的key required:这个参数是否必须的
     *                       defaultValue:默认值。没带默认是null;
     *
     *
     * @RequestHeader:获取请求头中某个key的值; request.getHeader("User-Agent");
     * @RequestHeader("User-Agent")String userAgent userAgent =
     *                                    request.getHeader("User-Agent")
     *                                    如果请求头中没有这个值就会报错; value() required()
     *                                    defaultValue()
     *
     * @CookieValue:获取某个cookie的值; 以前的操作获取某个cookie; Cookie[] cookies =
     *                            request.getCookies(); for(Cookie c:cookies){
     *                            if(c.getName().equals("JSESSIONID")){ String
     *                            cv = c.getValue(); } }
     * value()
     * required()
     * defaultValue()
     */
    @RequestMapping("/handle01")
    public String handle02(
            @RequestParam(value = "user", required = false, defaultValue = "你没带") String username,
            @RequestHeader(value = "AHAHA", required = false, defaultValue = "她也没带") String userAgent,
            @CookieValue(value="JSESSIONID",required=false)String jid) {
        System.out.println("这个变量的值:" + username);
        System.out.println("请求头中浏览器的信息:" + userAgent);
        System.out.println("cookie中的jid的值"+jid);
        return "success";
    }

    /**
     * 如果我们的请求参数是一个POJO;
     * SpringMVC会自动的为这个POJO进行赋值?
     * 1)、将POJO中的每一个属性,从request参数中尝试获取出来,并封装即可;
     * 2)、还可以级联封装;属性的属性
     * 3)、请求参数的参数名和对象中的属性名一一对应就行
     *
     *
     * 提交的数据可能有乱码:
     * 请求乱码:
     *         GET请求:改server.xml;在8080端口处URIEncoding="UTF-8"
     *         POST请求:
     *             在第一次获取请求参数之前设置
     *             request.setCharacterEncoding("UTF-8");
     *             自己写一个filter;SpringMVC有这个filter
     *
     * 响应乱码:
     *         response.setContentType("text/html;charset=utf-8")
     * @param book
     * @return
     */
    @RequestMapping("/book")
    public String addBook(Book book){
        System.out.println("我要保存的图书:"+book);
        return "success";
    }

    /**
     * SpringMVC可以直接在参数上写原生API;
     *
     * HttpServletRequest
     * HttpServletResponse
     * HttpSession
     *
     *
     * java.security.Principal
     * Locale:国际化有关的区域信息对象
     * InputStream:
     *         ServletInputStream inputStream = request.getInputStream();
     * OutputStream:
     *         ServletOutputStream outputStream = response.getOutputStream();
     * Reader:
     *         BufferedReader reader = request.getReader();
     * Writer:
     *         PrintWriter writer = response.getWriter();
     *
     * @throws IOException

     *
     *
     */
    @RequestMapping("/handle03")
    public String handle03(HttpSession session,
            HttpServletRequest request,HttpServletResponse response) throws IOException {
        request.setAttribute("reqParam", "我是请求域中的");
        session.setAttribute("sessionParam", "额我是Session域中的");

        return "success";
    }

}

3.2 数据输出

如何将数据带给页面

/**
 * SpringMVC除过在方法上传入原生的request和session外还能怎么样把数据带给页面
 *
 * 1)、可以在方法处传入Map、或者Model或者ModelMap。
 *      给这些参数里面保存的所有数据都会放在请求域中。可以在页面获取
 *   关系:
 *      Map,Model,ModelMap:最终都是BindingAwareModelMap在工作;
 *      相当于给BindingAwareModelMap中保存的东西都会被放在请求域中;
 *
 *      Map(interface(jdk))      Model(interface(spring)) 
 *          ||                          //
 *          ||                         //
 *          \/                        //
 *      ModelMap(clas)               //
 *                  \\              //
 *                   \\            //
 *                  ExtendedModelMap
 *                          ||
 *                          \/
 *                  BindingAwareModelMap
 *
 * 2)、方法的返回值可以变为ModelAndView类型;
 *          既包含视图信息(页面地址)也包含模型数据(给页面带的数据);
 *          而且数据是放在请求域中;
 *          request、session、application;
 *          
 *
 * @author lfy
 *
 */
@Controller
public class OutputController {
    
    @RequestMapping("/handle01")
    public String handle01(Map<String, Object> map){
        map.put("msg", "你好");
        System.out.println("map的类型:"+map.getClass());
        return "success";
    }
    
    /**
     * Model:一个接口
     * @param model
     * @return
     */
    @RequestMapping("/handle02")
    public String handle02(Model model){
        model.addAttribute("msg", "你好坏!");
        System.out.println("model的类型:"+model.getClass());
        return "success";
    }
    
    @RequestMapping("/handle03")
    public String handle03(ModelMap modelMap){
        modelMap.addAttribute("msg", "你好棒!");
        System.out.println("modelmap的类型:"+modelMap.getClass());
        return "success";
    }
    
    /**
     * 返回值是ModelAndView;可以为页面携带数据
     * @return
     */
    @RequestMapping("/handle04")
    public ModelAndView handle04(){
        //之前的返回值我们就叫视图名;视图名视图解析器是会帮我们最终拼串得到页面的真实地址;
        //ModelAndView mv = new ModelAndView("success");
        ModelAndView mv = new ModelAndView();
        mv.setViewName("success");
        mv.addObject("msg", "你好哦!");
        return mv;
        
    }

}

3.3 ModelAttribute

使用场景:
1)页面:
在这里插入图片描述
2)dao:全字段更新。没带的字段会在数据库中更新为null;

/**
 * 测试ModelAttribute注解;
 * 使用场景:书城的图书修改为例;
 * 1)页面端;
 *      显示要修改的图书的信息,图书的所有字段都在
 * 2)servlet收到修改请求,调用dao;
 *      String sql="update bs_book set title=?,
 *                  author=?,price=?,
 *                  sales=?,stock=?,img_path=?
 *              where id=?";
 * 3)实际场景?
 *      并不是全字段修改;只会修改部分字段,以修改用户信息为例;
 *      username  password  address;
 *      1)、不修改的字段可以在页面进行展示但是不要提供修改输入框;
 *      2)、为了简单,Controller直接在参数位置来写Book对象
 *      3)、SpringMVC为我们自动封装book;(没有带的值是null)
 *      4)、如果接下来调用了一个全字段更新的dao操作;会将其他的字段可能变为null;
 *          sql = "update bs_book set"
 *          if(book.getBookName()){
 *              sql +="bookName=?,"
 *          }
 *          if(book.getPrice()){
 *              sql +="price=?"
 *          }
 *
 * 4)、如何能保证全字段更新的时候,只更新了页面携带的数据;
 *      1)、修改dao;代价大?
 *      2)、Book对象是如何封装的?
 *          1)、SpringMVC创建一个book对象,每个属性都有默认值,bookName就是null;
 *              1、让SpringMVC别创建book对象,直接从数据库中先取出一个id=100的book对象的信息
 *              2、Book [id=100, bookName=西游记, author=张三, stock=12, sales=32, price=98.98]
 *
 *          2)、将请求中所有与book对应的属性一一设置过来;
 *              3、使用刚才从数据库取出的book对象,给它 的里面设置值;(请求参数带了哪些值就覆盖之前的值)
 *              4、带了的字段就改为携带的值,没带的字段就保持之前的值
 *          3)、调用全字段更新就有问题;
 *              5、将之前从数据库中查到的对象,并且封装了请求参数的对象。进行保存;
 *
 * @author lfy
 */
@Controller
public class ModelAttributeTestController {
    
    private Object o1;
    private Object o2;
    
    private Object b1;
    private Object b2;
    
    //bookDao.update(book);
    //Book [id=100, bookName=null, author=张三, stock=12, sales=32, price=98.98]
    /**
     *      String sql="update bs_book set bookName=?,
                    author=?,price=?,
                    sales=?,stock=?,img_path=?
                where id=?";
     */
    /**
     * 可以告诉SpringMVC不要new这个book了我刚才保存了一个book;

     * 哪个就是从数据库中查询出来的;用我这个book?@ModelAttribute("haha")
     *
     * 
     * 同都是BindingAwareModelMap
     * @param book
     * @return
     */
    @RequestMapping("/updateBook")
    public String updateBook(@ModelAttribute("haha")Book book,Map<String, Object> model){
        o2 = model;
        b2  = book;
        Object haha = model.get("haha");
        //System.out.println("传入的model:"+model.getClass());
        System.out.println("o1==o2?"+(o1 == o2));
        System.out.println("b1==b2?"+(b1 == b2)+"-->"+(b2 == haha));
        
        System.out.println("页面要提交过来的图书信息:"+book);
        return "success";
    }
    
    /**
     * 1)、SpringMVC要封装请求参数的Book对象不应该是自己new出来的。
     *      而应该是【从数据库中】拿到的准备好的对象
     * 2)、再来使用这个对象封装请求参数
     *
     * @ModelAttribute:
     *      参数:取出刚才保存的数据
     *      方法位置:这个方法就会提前于目标方法先运行;
     *          1)我们可以在这里提前查出数据库中图书的信息
     *          2)将这个图书信息保存起来(方便下一个方法还能使用)
     *
     * 参数的map:BindingAwareModelMap
     */
    @ModelAttribute
    public void hahaMyModelAttribute(Map<String, Object> map){
        
        Book book = new Book(100, "西游记", "吴承恩", 98, 10, 98.98);
        System.out.println("数据库中查到的图书信息是:"+book);
        map.put("haha", book);
        b1 = book;
        o1 = map;
        System.out.println("modelAttribute方法...查询了图书并给你保存起来了...他用的map的类型:"+map.getClass());
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值