Springmvc学习

1.入门案例

1.新建一个web maven工程,使用web-app 骨架,如果我们有下载过骨架,那么在第三步Properties中添加键值对archetypeCatalog=internal即使用本地仓库的骨架,避免创建maven工程时去网上下载,可以缩短时间。
2.添加依赖 spring-context,spring-webmvc,spring-web,servlet-api,jsp-api.
3.在web.xml中添加前端控制器:

  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

4.配置tomcat服务器,在Deployment中添加我们当前项目,然后配置好热部署
5.重新创建index.jsp文件作为请求页面,并写入请求代码,创建控制器类,并写入请求的方法,和返回参数
6.创建spring配置文件,导入约束(除了基本的还需包含context和mvc),开启注解扫描,开启springmvc注解,配置Controller,RequestMapping注解在控制器类中


    <!--开启自动扫描的包-->
    <context:component-scan base-package="com.qjw"></context:component-scan>
    <!--添加视图解析器-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!--开启springmvc的注解-->
    <mvc:annotation-driven></mvc:annotation-driven>

7.在web.xml中配置spring.xml文件的加载:

  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--配置Servlet初始化参数,用来加载我们的spring配置文件-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

8.在控制器中配置return参数,并在WEB-INF新建一个pages用来返回请求成功的页面
9.在spring中配置视图解析器

 <!--添加视图解析器-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--配置前缀和后缀-->
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

10.在请求页面填入访问地址需要和控制器方法中的RequestMapping中的path或者value的路径或者值一致,一般我们在RequestMapping path或者value中配置了/,那么在请求页面就不用加/了。
11. RequestMapping的属性

  1. path 指定请求路径的url
  2. value value属性和path属性是一样的
  3. mthod 指定该方法的请求方式
  4. params 指定限制请求参数的条件(指定参数,返回一个String类型,如果请求的参数不一致(key和value的名字要一致),则不能访问)
  5. headers 发送的请求中必须包含的请求头

2.请求参数及自定义类型转换

1.请求参数(基本数据类型和字符串类型)
在jsp页面编写请求参数:

<h1><a href="param/paramtest1?username=aa&password=123">请求参数为基本数据类型和字符串</a></h1>

然后在Conroller类中:

    @RequestMapping("/paramtest1")
    //在要请求的方法中加入参数,参数名必须和请求的一致,即上面的username=aa必须和参数的username一致
    public String paramTest(String username,int password)
    {
     
        System.out.println("请求成功,取得参数:"+username+"和"+password);
        return "success";
    }

2.请求参数(实体类(javaBean对象))
1.创建提交表单的页面:

<body>
      <form action="javabean/saveaccount">
          <!--name的值需和要请求的javabean的属性名一致-->
          姓名:<input type="text" name="name"></br>
          年龄:<input type="text" name="age"></br>
          存款:<input type="text" name="account"></br>
          <!--引用名.属性名-->
          用户名:<input type="text" name="user.username"></br>
          密码:<input type="text" name="user.password"></br>
          <input type="submit" value="提交">
      </form>

</body>

2.创建实体类或者javaBean类:

public class UserAccount {
     
   private String name;
   private int age;
   private String account;
   private User user;
....
public class User implements Serializable {
     
    private String username;
    private String password;
    ....

生成对应的get,set,toString方法,表单中的name属性要和javabean中的属性名一致,如果有引用类型的属性,那么采用引用名.属性名的方式,也需要一致
3.创建控制器类

@Controller
@RequestMapping("/javabean")
public class JavaBeanParamDemo {
     

    @RequestMapping("/saveaccount")
    //这里参数需要填表单所需要提交到哪个javabean
    public String saveAccount(UserAccount useraccount)
    {
     
        System.out.println("请求成功:"+"\n"+useraccount);
        return "success";
    }
}

4.返回结果:
在这里插入图片描述
3.请求参数(集合类型)
1.写个表单用来提交数据:要注意的就是集合请求的方式

<form action="javabean/saveaccount">
              <!--name的值需和要请求的javabean的属性名一致-->
              姓名:<input type="text" name="name"></br>
              年龄:<input type="text" name="age"></br>
              存款:<input type="text" name="account"></br>
              <!--集合引用名.对应类型的属性名-->
              List用户名:<input type="text" name="myList[0].username"></br>
              List密码:<input type="text" name="myList[0].password"></br>
              Map用户名:<input type="text" name="myMap[0].username"></br>
              Map密码:<input type="text" name="myMap[0].password"></br>
              <input type="submit" value="提交">
          </form>

2.修改javabean类,生成get,set,toString方法

public class UserAccount {
     
   private String name;
   private int age;
   private String account;
   private List<User> myList;
   private Map<String,User> myMap;
   ....

3.控制类不变

@Controller
@RequestMapping("/param")
public class RequestParamDemo1 {
     

    @RequestMapping("/paramtest1")
    //在要请求的方法中加入参数,参数名必须和请求的一致,即上面的username=aa必须和参数的username一致
    public String paramTest(String username,int password)
    {
     
        System.out.println("请求成功,取得参数:"+username+"和"+password);
        return "success";
    }
}

4.结果:
在这里插入图片描述
4.解决中文乱码(如果在传参时传表单输入中文,控制台输出乱码,注意,过滤器在web.xml中的位置要在Servlet前面)
解决办法:设置过滤器
在web.xml中

 <!--中文乱码过滤器-->
  <filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <!--初始化参数,指定encoding属性为utf-8-->
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <!--拦截所有-->
    <url-pattern>/*
  

5.自定义类型转换器
描述:当我们进行参数传值的时候,大多数类型转换情况springmvc已经帮我们做完了,比如String->int,但是如果有它没有定义的转换类型,那么我们就要自己编写一个类型转换器
以Data类型为例:比如2019/10/21 springmvc能帮我们转换为日期类型,但是2019-10-21就不行了
1.写好提交页面

 <form action="javabean/saveaccount">
         姓名:<input type="text" name="name"><br>
         年龄:<input type="text" name="age"><br>
         生日:<input type="text" name="date"><br>
         <input type="submit" value="提交">
     </form>

2.修改javabean

public class UserAccount {
     
        private String name;
        private int age;
        private Date date;
        ....

3.写自定义类型转换器类

//我们自定义的转换器必须实现springmvc的转换器接口Converter
public class DateConverter implements Converter<String,Date> {
     


    @Override
    public Date convert(String source) {
     
        if (source==null){
     
            System.out.println("日期输入为空!");
        }
        DateFormat date=new SimpleDateFormat("yyyy-mm-dd");
        try {
     
            return date.parse(source);
        } catch (Exception e) {
     
            throw new RuntimeException("类型转换出错!");
        }

    }

4.最后在spring.xml文件中,将我们自定义的类型转换器类加入到springmvc的类型转换器的set集合中

  <!---配置自定义类型解析器-->
    <bean id="converterService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <!--这是解析器里的一个属性-->
        <property name="converters">
            <set>
                <!--转换器类路径-->
                <bean class="com.qjw.util.DateConverter"></bean>
            </set>
        </property>
    </bean>
    
    <!--开启springmvc的注解-->
    <!--将自定义的类型转换配置生效-->
    <mvc:annotation-driven conversion-service="converterService"></mvc:annotation-driven>

结果:
在这里插入图片描述

6.获取Servlet原生的api

1.jsp页面

<a href="javabean/servletapi">获取原生servletapi</a>

2.控制器

    @RequestMapping("/servletapi")
    //想要获取什么,参数就填什么
    public String servletApi(HttpServletRequest request, HttpServletResponse response)
    {
     
        System.out.println("请求成功");
        HttpSession session=request.getSession();
        System.out.println(session);
        ServletContext context=session.getServletContext();
        System.out.println(context);
        System.out.println(response);
        return "success";


    }

3.结果说明已经获取到了对象地址
Springmvc学习_第1张图片

2.常用注解

1.RequestParam注解
作用:把请求中的指定名称的参数传递给控制器中的形参赋值
属性
value:请求参数中的名称
required:请求参数中是否必须提供此参数,默认值是true,必须提供(这个参数是说这个参数为true的时候,那么请求参数中的name必须和RequestParam中的name或者value值一致,否则不能传值)

1.新建jsp文件

<body>
<h1><a href="annon/requestparam?name=你好">RequestParam注解</a></h1>
</body>

2.新建控制器类

@Controller
@RequestMapping("/annon")
public class AnnotationDemo {
     

    @RequestMapping("/requestparam")
    //可以发现RequestParam注解中的name和请求参数后面的name是一样的,然后@RequestParam将name值赋给了方法的参数usename
    public String testRequestParam(@RequestParam(name="name")String usename)
    {
     
        System.out.println(usename);
        return "success";
    }
}

3.结果
在这里插入图片描述
2.RequestBody注解
作用:用于获取请求体的内容(注意:get方法不可以)
属性
required:是否必须有请求体,默认值是true

1.jsp页面

<form action="annon/requestbody" method="post">
        用户名:<input type="text" name="username"><br>
        密码:<input type="text" name="password"><br>
        <input type="submit" value="提交">
    </form>

2.控制器

  //@RequestBody
    @RequestMapping("/requestbody")
    public String testRequestBody(@RequestBody String body)
    {
     
        System.out.println(body);
        return "success";
    }

注意,这里的参数必须要和表单中的参数不同,不然spring会进行默认参数匹配,我们要拿的是请求体
3.结果
在这里插入图片描述
3.PathVariable注解
作用:拥有绑定url中的占位符的。例如:url中有/delete/{id},{id}就是占位符
属性:
value:指定url中的占位符名称

Restful风格的URL:
请求路径一样,可以根据不同的请求方式去执行后台的不同方法
restful风格的URL优点
结构清晰
符合标准
易于理解
扩展方便

1.jsp页面

<!--这里只要路径直接/值就行了-->
<h1><a href="annon/pathvariable/10">PathVariable注解</a></h1>

2.控制器

   /**
     * 注解@PathVariable
     * @param
     * @return
     */
    @RequestMapping("/pathvariable/{sid}")
    public String testPathVariable(@PathVariable(name= "sid") String id){
       //拿到sid的值=10赋值给id,然后打印出来
        System.out.println(id);
        return "success";
    }

这里@PathVariable中的sid必须和 @RequestMapping("/pathvarivale/{sid}")中的sid一致,且jsp页面必须传入一个值,如上的href="annon/pathvariable/10
3.结果
在这里插入图片描述
4. HiddentHttpMethodFilter注解
作用:
由于浏览器 form 表单只支持 GET 与 POST 请求,而 DELETE、PUT 等 method 并不支持,Spring3.0 添
加了一个过滤器,可以将浏览器请求改为指定的请求方式,发送给我们的控制器方法,使得支持 GET、POST、PUT
与 DELETE 请求。
使用方法:
第一步:在 web.xml 中配置该过滤器。
第二步:请求方式必须使用 post 请求。
第三步:按照要求提供_method 请求参数,该参数的取值就是我们需要的请求方式。

不常用,了解一下就可,因为RestFule中有个WebClient类能调用各种静态方法从而帮我们实现各种请求,或者用浏览器插件来模拟

5. RequestHeader注解
RequestHeader注解
作用:获取指定请求头的值
属性
value:请求头的名称
没多大用处

6.CookieValue注解
作用:用于获取指定cookie的名称的值
属性
value:cookie的名称

1.jsp页面

<h1><a href="annon/cookievalue">CookieValue注解</a></h1>

2.控制器

    /**
     * 注解@CookieValue
     * @param
     * @return
     */
    @RequestMapping("/cookievalue")
    public String testCookieValue(@CookieValue(value = "JSESSIONID") String cookievalue){
     
        System.out.println(cookievalue);
        return "success";
    }

这里我们获取浏览器返回的JSESSIONID,也就是jsessionid
结果:
在这里插入图片描述
7.ModelAttribute注解
作用
出现在方法上:表示当前方法会在控制器方法执行前线执行。
出现在参数上:获取指定的数据给参数赋值。
应用场景
当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。
例如
我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数
据是肯定没有此字段的内容,一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题。

1.jsp页面

<form action="annon/modelattribute" >
    用户名:<input type="text" name="name"><br>
    年龄:<input type="text" name="age"><br>
    <input type="submit" value="提交">
</form>

2.javabean生成get,set,toString方法

public class UserAccount implements Serializable{
     
        private String name;
        private int age;
        private Date date;
        ....

3.控制器

 /**
     * 注解@ModelAttribute
     * @param
     * @return
     */
    @RequestMapping("/modelattribute")
    public String testmodelAttribute(UserAccount userAccount){
     
        System.out.println(userAccount);
        return "success";
    }
    //这里name用于取得页面传入的参数name的值然后从数据库根据name查询取出date
    @ModelAttribute
    public UserAccount addAttribute(String name)
    {
     
        //模拟从数据库查询日期然后给对象赋值
        UserAccount userAccount=new UserAccount();
        userAccount.setDate(new Date());
        return userAccount;
    }

4.结果
在这里插入图片描述
分析:这是@ModelAttribute第一种有返回值的作用于方法的方式,因为有了@ModelAttribute注解,被注解的方法优先于请求的方法执行,所以我们能先获取到name,查询之后给UserAccount赋值然后返回该对象执行请求的方法testmodelAttribute,然后请求页面传的参数也赋值到了javabean上,最后得到该对象

第二种方法,没有返回值类型
只改变控制器中的方法
1.控制器

 /**
     * 注解@ModelAttribute
     * @param
     * @return
     */
    @RequestMapping("/modelattribute")
    public String testmodelAttribute(@ModelAttribute("abc") UserAccount userAccount){
     
        System.out.println(userAccount);
        return "success";
    }
    //这里name用于取得页面传入的参数name的值然后从数据库根据name查询取出date
    @ModelAttribute
    public void addAttribute(String name, Map<String,UserAccount> map)
    {
     
        //模拟从数据库查询日期然后给对象赋值
        UserAccount userAccount=new UserAccount();
        userAccount.setDate(new Date());
        map.put("abc",userAccount);
    }

分析:这种方法在于将根据name到数据库查询到date,将该date存入到一个map集合中,然后在请求方法参数中使用@ModelAttribute注解将值abc赋给userAccount对象。

8.SessionAttributes注解
作用:用于多次执行控制器方法间的参数共享,进行存储,读取数据,且这个注解只能作用于类上.
用于将数据存进Request域中,比如在请求页面将数据存入request域,然后在控制台执行跳转到成功页面,再从成功页面取的存入的值。
那为什么不用前面的使用原生的servlet API呢?因为这样会造成程序耦合性过高,比如编译期必须提供servletAPI才能编译成功,所以springMVC为
我们提供了一个接口Model,这个Model有个实现类ModelMap,而这个ModelMap又继承与ListHashMap,所以我们就将要存入的值相当于存入到一个map中
那么问题来了,怎么存呢?
1.存储数据(后台将数据存储到Request域中)
请求jsp页面:

<h1><a href="annon/sessionattributes">SessionAttributes注解</a></h1>

2.控制器

 @RequestMapping("/sessionattributes")
    //Model用于存入数据
    public String testSessionAttributes(Model model)
    {
     
        System.out.println("请求成功!");
        model.addAttribute("name","你好");
        return "success";
    }

3.结果页面,如果不能显示,那么在<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false"%>加上isELIgnored="false"即可加载el表达式

<body>
       ${
      requestScope}
</body>

结果:
在这里插入图片描述
说明后台的数据被存入到了Request域中

如果我们加上SessionAttributes注解,即在控制类上加上该注解

@Controller
@RequestMapping("/annon")
@SessionAttributes(value = {
     "name"})//如果加上这个注解,那么相当于把数据存入到了Session域中,注意,前面演示的例子数据只存进了Request域中
public class AnnotationDemo {
     

那么我们在结果页面:

<body>
      <!--Request域中也可以直接${
     name}取值-->
      Request域中取出的值: ${
      requestScope.name}<br>

      Session域中取出的值: ${
     sessionScope}
</body>

结果:
在这里插入图片描述
如果存到Session域中了,我们怎么取值?和删除值呢?
控制器:


    /**
     * 用于从后台取出Session中的值,用ModelMap来获取值
     */
    @RequestMapping("/getsessionattributes")
    public String testGetSessionAttributes(ModelMap modelMap)
    {
     
        System.out.println("取出成功!");
        String msg=(String)modelMap.get("name");
        System.out.println(msg);
        return "success";
    }

    /**
     * 从后台删除Session中的值,参数调用方法就是删除
     */
    @RequestMapping("/delsessionattributes")
    public String testDelSessionAttributes(SessionStatus status)
    {
     
        System.out.println("删除成功!");
        status.setComplete();
        return "success";
    }

依次点击
成功页面
Springmvc学习_第2张图片
你会发现第一个是设置值,第二个是获取值,第三个是删除值,注意第三个删除的只是Session域中的值,Request中的并没有被删除
结果图:
设置:
在这里插入图片描述
获取:
在这里插入图片描述
删除:
在这里插入图片描述
如果你疑惑为什么设置和获取是一样的?那么我和你说我们第一个页面只是为了知道我们设置成功而已

3.返回值类型及响应数据类型

这里说的返回值是控制器的方法,也就是发送请求的页面需要请求的映射方法
1.返回字符串类型
描述:请求页面给我们发来一个请求,我们根据请求的内容到数据库查询然后将查询结果存到Model中,最后在结果页面从Request域中根据key获取存入的字符串。
1.请求页面

<body>

<h1><a href="user/testresponsestring">请求服务器</a></h1>

</body>

2.javabean

public class User implements Serializable {
     

    private String name;
    private int age;
    private String sex;
    ....

3.控制器

@Controller
@RequestMapping("/user")
public class TestResponseString {
     

    @RequestMapping("/testresponsestring")
    public String testResponseString(Model model)
    {
     
        //这里模拟一个从数据库查询返回的对象,然后存入Model中
        User user=new User();
        user.setName("小明");
        user.setAge(18);
        user.setSex("男");
        System.out.println(user);
        model.addAttribute("user",user);
        return "success";

    }
}

4.结果页面

<body>
<!--跳转页面从Request域中根据key取值-->
<h2>请求成功!</h2><br>
<h1>姓名:${
     user.name}  年龄:${
     user.age} 性别:${
     user.sex}</h1>
</body>

结果:
Springmvc学习_第3张图片

2.返回值是void类型
1.jsp页面

<h1><a href="user/testresponsevoid">请求服务器Void</a></h1>

2.控制器

@RequestMapping("/testresponsevoid")
    public void testResponseVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     
        //方法一:用请求转发到成功页面
        //request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);

        //方法二:重定向(重定向不能访问WEB-INF下的文件,所以我们访问webapp下的index.jsp)
        //response.sendRedirect(request.getContextPath()+"/index.jsp");

        //方法三:直接响应
        //设置中文乱码
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().print("你好");

    }

3.返回值是ModelView对象

1.jsp页面


<h1><a href="user/testResponseModelAndView">请求服务器ModelAndView</a></h1>

2.控制器

  @RequestMapping("/testResponseModelAndView")
    public ModelAndView testResponseModelAndView() {
     
        //创建一个springmvc给我们提供的ModelAndView对象
        ModelAndView mv = new ModelAndView();
        //这里模拟一个从数据库查询返回的对象,然后存入Model中
        User user = new User();
        user.setName("小明");
        user.setAge(18);
        user.setSex("男");
        System.out.println(user);
        mv.addObject("user", user);
        mv.setViewName("success");
        return mv;
    }

这里注意,返回值是ModelAndView,将对象加入到ModelAndView用addObject(),跳转页面用setName().

3.用关键字来表示请求转发和重定向
不常用,但是需了解
1.控制器

    //请求转发和重定向使用关键字的方式
    @RequestMapping("/testForwardAndRedirect")
    public String testForwordAndRedirect() {
     
        //请求转发方式
        //return "forward:/WEB-INF/pages/success.jsp";

        //重定向方式,注意只能请求项目根目录下的文件
        return "redirect:/index.jsp";


    }

这样就ok了

4.ResponeBody响应json数据(示例在5)
准备工作:
1.在webapp下创建js文件,然后引入jquery文件(注意是webapp下创建,不是WEB-INF
2.新建respone.jsp请求页面

1.请求页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script src="js/jquery.min.js"></script>
    <script>
        $(function () {
     
            $("#btn").click(function () {
     
                alert("你好");
            });
        });
    </script>
</head>
<body>

<button id="btn">发送Ajax请求</button>
</body>
</html>

2.因为我们引入了jquery文件,但是我们配置的前端控制器DispatcherServlet会拦截所有请求,所以我们需要在spring.xml文件中配置:

  <!--配置前端控制器哪些静态资源不会被拦截,mapping和映射地址有关,location和服务器请求资源有关-->
    <mvc:resources location="/js/" mapping="/js/**"/>
    <mvc:resources location="/css/" mapping="/css/**"/>
    <mvc:resources location="/amages/" mapping="/amages/**"/>

这样当我们点击button时,会弹出一个响应

5.发送AJAX请求
准备工作:
1.json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包
有了这个jackson的jar包,当我们客户端向服务器发送json数据的时候,如果发送的数据的key和我们的控制器方法参数对象的属性相同,那么就会自动把数据给我们封装到javabean对象中

 <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.8</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.0</version>
    </dependency>

    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.8</version>
    </dependency>

2.编写AJAX请求页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script src="js/jquery.min.js"></script>
    <script>
       $(function () {
     
           $("#btn").click(function () {
     
               //这是原始的发送Ajax请求,直接$.get(),$.post()底层其实都是调用的这个
               $.ajax({
     
                   //请求控制器的地址映射
                   url:"user/testAjaxRequest",
                   //设置客户端向服务端发送的数据类型和编码
                   contentType:"application/json;charset=utf-8",
                   //客户端发送的数据
                   data:'{"name":"小红","age":"18","sex":"女"}',
                   //设置服务端返回的数据类型为json
                   dataType:"json",
                   //设置请求方式
                   type:"post",
                   //返回成功接收数据的函数,data为封装的服务器返回的数据,这里是json
                   success:function (data) {
     
                       alert(data.name+data.age+data.sex);

                   }

               });
           });
       });
    </script>
</head>
<body>
<button id="btn">发送Ajax请求</button>
</body>
</html>

3.控制器类

    //RequestBody用于将服务器请求的json数据转换成我们的javabean(这里是User)对象
    // ResponseBody用于将我们的javabean(这里是User)对象转换成Json数据返回
    @RequestMapping("/testAjaxRequest")
    public @ResponseBody User testAjaxRequest(@RequestBody User user)
    {
     
        //打印看看有没有收到客户端发送过来的数据
        System.out.println(user);
        //模拟客户端请求,并去数据库查找返回数据,把年龄改为22传回客户端
        user.setAge(22);
        return user;
    }

4.结果
Springmvc学习_第4张图片
Springmvc学习_第5张图片

4.文件上传

1.springmvc文件上传
1.准备工作
文件上传的必要前提:

  1. form表单的enctype取值必须为multipart/form-data(默认值是:application/x-www-form-urlencoded),enctype:是表单请求正文的类型
  2. method 属性取值必须是 Post
  3. 提供一个文件选择域
    文件上传的原理分析:
    当 form 表单的 enctype 取值不是默认值后,request.getParameter()将失效。 enctype=”application/x-www-form-urlencoded”时,form 表单的正文内容是:
    key=value&key=value&key=value
    当 form 表单的 enctype 取值为 Mutilpart/form-data 时,请求正文内容就变成:
    每一部分都是 MIME 类型描述的正文
-----------------------------7de1a433602ac 分界符
Content-Disposition: form-data; name="userName" 协议头
aaa 协议的正文
-----------------------------7de1a433602ac
Content-Disposition: form-data; name="file"; 
filename="C:\Users\zhy\Desktop\fileupload_demofile\b.txt"
Content-Type: text/plain 协议的类型(MIME 类型)
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-----------------------------7de1a433602ac--

2.借助第三方组件实现上传
使用 Commons-fileupload 组件实现文件上传,需要导入该组件相应的支撑 jar 包:commons-fileupload
commons-io。commons-io 不属于文件上传组件的开发 jar 文件,但Commons-fileupload 组件从 1.1 版本开始,它
工作时需要 commons-io 包的支持。

3.使用springmvc进行文件上传必须在spring.xml配置springmvc给我们提供的文件解析器:

 <!--这里的id值必须为multipartResolver,然后我们指定了上传文件字节大小最大为10M,也就是10*1024*1024=10485760-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10485760"></property>
    </bean>

4.编写上传页面

<body>

    <h2><a href="user/fileUpLoad01">请求服务器!</a></h2>

    <form action="user/fileUpLoad02" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload"/><br/>
        <input type="submit" value="提交"/>

    </form>
</body>

5.控制器类

    //需要传入参数HttpServletRequest和MultipartFile,且这里MultipartFile的引用upload必须和jsp页面文件标签的name一致
    @RequestMapping("/fileUpLoad02")
    public String fileUpLoadDemo2(HttpServletRequest request, MultipartFile upload) throws Exception
    {
     
        //获取要上传文件的位置
        String path=request.getSession().getServletContext().getRealPath("/upload/");
        File file=new File(path);
        if (!file.exists())
        {
     
            file.mkdir();
        }
        //获取上传文件的名称
        String fileName=upload.getOriginalFilename();
        //把文件名称设置为唯一ID值
        String uuid= UUID.randomUUID().toString().replace("-","");
        fileName=uuid+"_"+fileName;
        //上传文件
        upload.transferTo(new File(path,fileName));

        return "success";
    }

2.不同服务器之间的文件上传

简介:在实际开发中,我们会有很多处理不同功能的服务器。例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
缓存和消息服务器:负责处理大并发访问的缓存和消息
文件服务器:负责存储用户上传文件的服务器。
(注意:此处说的不是服务器集群)

准备工作:
为了实现跨服务器,sun公司为我们提供了2个jar包,需要导入依赖(是在我们的应用服务器导入)

<dependency> 
<groupId>com.sun.jersey</groupId> 
<artifactId>jersey-core</artifactId> 
<version>1.18.1</version> 
</dependency> 
<dependency> 
<groupId>com.sun.jersey</groupId> 
<artifactId>jersey-client</artifactId> 
<version>1.18.1</version> 
</dependency>

创建一个module(模块),选择web-app骨架,然后选none,输入项目名,创建好项目之后
Springmvc学习_第6张图片
配置好tomcat服务器,其中1,2,3地方需要和我们的应用服务器(也就是图片上传的那个工程)不同,选择我们当前项目配置好就ok了
Springmvc学习_第7张图片
启动第二个服务器,弹出helloword页面说明服务器启动成功
1.准备就绪,编写jsp页面

跨服务器上传文件:
    <form action="user/fileUpLoad03" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="upload"/><br/>
        <input type="submit" value="提交"/>

    </form>

2.控制器类

//跨服务器上传文件
    @RequestMapping("/fileUpLoad03")
    public String fileUpLoadDemo3(MultipartFile upload) throws Exception
    {
     
        System.out.println("请求成功!");
        //获取文件要上传的服务器路径,然后加上文件夹upload路径后面加个/方便后面不用填写,这里注意
        //我们需要手动去文件服务器项目下(磁盘下)创建一个uploads文件
        //这边的path地址是第二个Tomcat配置中的URL加上uploads
        String path="http://localhost:9090/fileuploadserver/uploads/";
   
        //获取上传文件的名称
        String fileName=upload.getOriginalFilename();
        //把文件名称设置为唯一ID值
        String uuid= UUID.randomUUID().toString().replace("-","");
        fileName=uuid+"_"+fileName;
        //创建客户端对象
        Client client=Client.create();
        //和图片服务器进行连接,这里path后面就不用再加"/"了因为第一步我们获取路径的后面加了返回一个WebResource对象
        WebResource webResource=client.resource(path+fileName);
        //上传文件
        webResource.put(upload.getBytes());


        return "success";
    }

然后上传文件

最后,在启动的时候会出现各种错误比如403,405之类的,出现这些问题有2种解决办法
1.打开你Tomcat安装目录->conf->web.xml
Springmvc学习_第8张图片
加入

  <init-param>
            <param-name>readonly</param-name>
            <param-value>false</param-value>
  </init-param>

原因是因为Tomcat服务器默认不允许我们跨服务器上传文件,设置为false就好了
如果出现其他问题,请注意图片的名字,不要带中文,如果是中文要另外进行配置(请自行百度)

如果还出现错误,检查磁盘工程的目录下有没有uploads这个文件夹,或者idea文件服务器项目webapp下新建一个uploads文件夹,最后
改完最好重启项目和服务器吧

5.SpringMVC拦截器和异常处理

1.拦截器
Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
用户可以自己定义一些拦截器来实现特定的功能。
谈到拦截器,还要向大家提一个词——拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺
序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
说到这里,可能大家脑海中有了一个疑问,这不是我们之前学的过滤器吗?是的它和过滤器是有几分相似,但
是也有区别,接下来我们就来说说他们的区别:
过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。
拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。
过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。
拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦
截的。
它也是 AOP 思想的具体应用。
我们要想自定义拦截器, 要求必须实现:HandlerInterceptor 接口。
Springmvc学习_第9张图片
步骤
1.编写请求jsp

<body>

<a href="user/test">发送请求</a>

</body>

2.控制器类

@Controller
@RequestMapping("/user")
public class TestController {
     

    @RequestMapping("/test")
    public String TestDemo() throws Exception
    {
     
        System.out.println("请求成功");
      
        return "success";
    }
}

3.拦截器类

//必须要继承HandlerInterceptor
public class TestInterceptor implements HandlerInterceptor {
     
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
     
        System.out.println("拦截器执行");
        //返回true表示执行完该方法继续执行控制器中的方法
        //还可以在return直接进行请求转发等操作
        //request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
        return true;
    }
}

4.spring.xml

    <!--配置多个拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--拦截器需要拦截的映射,和控制器中的RequestMapping有关,如果要拦截所有控制器的方法用"/**"-->
            <mvc:mapping path="/user/*"/>
            <!--配置拦截器类-->
            <bean class="com.qjw.interceptor.TestInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

2.异常处理
在springmvc中异常是可以网上抛的
Springmvc学习_第10张图片
1.jsp页面

<body>

<a href="user/test">发送请求</a>

</body>

2.控制器类

  @RequestMapping("/test")
    public String TestDemo() throws Exception
    {
     
        System.out.println("请求成功");

        try {
     
        //模拟一个异常
            int a = 10 / 0;
        }catch (Exception e)
        {
     
            e.printStackTrace();
            throw new EntityException("查询异常");
        }
        return "success";
    }

3.创建异常类

public class EntityException extends Exception{
     
    private String message;

    public EntityException(String message) {
     
        this.message = message;
    }

    @Override
    public String getMessage() {
     
        return message;
    }

    public void setMessage(String message) {
     
        this.message = message;
    }
}

4.创建异常控制器类

//需要继承HandlerExceptionResolver
public class TestHandlerExceptionResolver implements HandlerExceptionResolver {
     
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception ex) {
     
        EntityException e=null;
        if (ex instanceof EntityException)
        {
     
                   e=(EntityException)ex;
        }else
        {
     
            e=new EntityException("系统正在维护");
        }
        //然后再用ModelAndView封装并跳转到友好的错误页面
        ModelAndView mv=new ModelAndView();
        mv.addObject("errorMsg",e.getMessage());
        mv.setViewName("error");

        return mv;
    }
}

你可能感兴趣的:(学习)