使用注解开发

我觉得可以跳过这个直接看springboot,因为在Spring第五版中已经摒弃了xml,写这些是为了更好的探究Spring及mvc原理。

首先在web.xml中配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-servlet.xml</param-value>
        </init-param>

        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

然后写里面需要的Spring配置文件,导入自动扫描包,设置不处理静态资源css,js,mp3,mp4啥的,开启注解支持

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.controller"/>
<!--    不处理静态资源-->
    <mvc:default-servlet-handler/>
    <mvc:annotation-driven/>
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
        <!--        前缀,后缀-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

写一个我们测试的页面

<%--
  Created by IntelliJ IDEA.
  Date: 2020/7/27
  Time: 2:41 下午
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>hello</title>
</head>
<body>
${msg}
</body>
</html>

接下来是注解简化的controller页面,model用来封装数据

@Controller
public class Hello {

    @RequestMapping("/hello")
    public String hello(Model model){
        model.addAttribute("msg","Hello MVC");
        return "hello";
    }
}

关于@RequestMapping,这个注解,我们可以看出它可以标示在方法上也可以直接标示在类上,标示在方法上直接使用这个路径就行,当标示在类上,默认为所有方法前都加了一层这个路径。

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    String name() default "";

    @AliasFor("path")
    String[] value() default {};

    @AliasFor("value")
    String[] path() default {};

    RequestMethod[] method() default {};

    String[] params() default {};

    String[] headers() default {};

    String[] consumes() default {};

    String[] produces() default {};
}

Restful Style

众所周知,在普通get请求时,提交的数据参数都会暴露在URL上面,我们来模拟一下,前端接受参数。

@Controller
public class Hello {

    @RequestMapping("/hello")
    public String hello(int a,int b,Model model){
        model.addAttribute("msg",a+b);
        return "hello";
    }
}

这时候当我们再次输入http://localhost:8080/hello就会报500错。因为我们这里有需要接受的参数。

模拟接受参数,http://localhost:8080/hello?a=1&b=1,页面就出来结果。

这是普通的get请求,我们使用restful风格来实现一下。

在Springmvc中我们可以使用@PathVariable注解,让方法参数对应绑定到一个URL模板变量上。

http://localhost:8080/hello/1/2 这时候我们调用这个页面即可得到我们需要的结果。

谈到视图跳转我们不得不讲到重定向和请求转发

!如果不想配置视图解析器的话,需要完整写出路径和后缀

转发

@Controller
public class Hello {

    @RequestMapping("/hello/{a}/{b}")
    public String hello(@PathVariable int a,@PathVariable int b, Model model){
        //转发
        model.addAttribute("msg",a+b);
        return "/WEB-INF/jsp/hello.jsp";
    }
}

重定向

@Controller
public class Hello {
    @RequestMapping("/hello/{a}/{b}")
    public String hello(@PathVariable int a,@PathVariable int b, Model model){
        //重定向
        model.addAttribute("msg",a+b);
        return "redirect:/index.jsp";
    }
}

重定向和转发的异同:

相同:页面都会实现跳转

不同:请求转发时URL不会变化

​ 重定向会变化

当我们写的参数与前端不匹配如何,这时候我们就需要一个注解来表明我们正式当提交域当名称。

@RequestMapping("t2")
public String test2(@RequestParam("username") String name){
    System.out.println(name);
    return "hello";
}

http://localhost:8080/t2?username=djsaldjs 这样就行了,再这里再次尝试restful风格(错误)

@RequestMapping("t2/{name}")
public String test2(@RequestParam("username") @PathVariable String name){
    System.out.println(name);
    return "hello";
}

畸形的请求语法。emmm畸形……

所以还是不要写奇怪的东西。

上面表现了普通的表单数据如何传输,但是当我们有实体类的时候如何呢?

我们写一个实体类User

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private int age;
}
@RequestMapping("t1")
public String test1(User user){
    System.out.println(user);
    return "hello";
}

我们直接把实体类作为参数传递。http://localhost:8080/t1?id=1&name=hello&age=8 前端会自动匹配字段,字段一致就ok,否则就null

乱码问题解决

首先我们先创建一个form.jsp

<%--
  Created by IntelliJ IDEA.
  Date: 2020/7/27
  Time: 5:19 下午
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/form" method="post">
    <input name="name">
    <input type="submit">
</form>
</body>
</html>

写一个路由,然后跳转输出表单接受的数据,在后台也打印一下

@Controller
public class Test {
    @RequestMapping("/aaa")
    public String form(){
        return "form";
    }
    @RequestMapping("/form")
    public String test(@RequestParam("name") String name, Model model){
           System.out.println(name);
        model.addAttribute("msg",name);
        return "hello";
    }
}

在表单界面打印我名字时,出现詹权武这里我们回到idea查看接受的数据,同样是詹权武

所以我们可以判定它在接收数据的时候就出现了乱码。

测试使用servlet中setcharacterencoding方法也是不可以的。

我们来通过过滤器来解决这个问题(/*注意)

  1. 使用原生的servlet过滤器
package com.filter;




import javax.servlet.*;
import java.io.IOException;

public class EncodingFilter implements Filter {


    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setCharacterEncoding("utf-8");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    public void destroy() {

    }
}

在xml中配置

<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>com.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
  1. 我们使用Spring中的过滤器
<filter>
    <filter-name>encoding</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>
</filter>
<filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

关于传递json

我们可以使用两个jar包

  1. jackson-databind
  2. fastjson

首先还是配置xml与写Spring配置文件。

测试需要我们可以写一个pojo类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private int id;
    private String name;
    private int age;
}

接下来可以写测试了,别忘了把controller包添加自动扫描,@RestController注解表示我们不会让返回的拼接成页面,而是直接作为字符串返回到前端,首先来测试基本用法,传递一个实体对象,(关于中文乱码问题,可以从@RequestMapping注解入手,也可以直接配置springmvc配置文件,有点懒就不写了)。

@RestController
public class Test {
    @RequestMapping("/j1")
    public String js1() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        User user = new User(1, "发", 2);
        return mapper.writeValueAsString(user);
    }

}

这时候我们想,如果传递一个List会怎么样?

 @RequestMapping("/j2")
    public String js2() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        User user1 = new User(2, "发", 2);
        User user2 = new User(5, "asdsa", 2);
        User user3 = new User(2, "发", 2);
        ArrayList<User> users = new ArrayList<User>();
        users.add(user1);
        users.add(user2);
        users.add(user3);
        return mapper.writeValueAsString(users);
    }

[{"id":2,"name":"?","age":2},{"id":5,"name":"asdsa","age":2},{"id":2,"name":"?","age":2}]可以看出就是json的数据类型格式。

如果是一个时间呢?普通的使用new Date方法返回的是一个时间戳,所以我们要转换它。这里使用java SimpleDateFormat方法。

 @RequestMapping("/j3")
    public String j3() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = sdf.format(date);
        return mapper.writeValueAsString(format);
    }

jackson也给我们提供了格式转换,其实也就是时间戳的关闭。

@RequestMapping("/j5")
public String j5() throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    mapper.setDateFormat(sdf);
    Date date = new Date();
    return mapper.writeValueAsString(date);
}

我们可以看出在上面写了许多许多重复代码,这不利于代码的简洁性,这时候我们就需要一个工具类。

public class Utils {
    public static String json(Object object,String sdf){
        ObjectMapper mapper = new ObjectMapper();
        SimpleDateFormat format = new SimpleDateFormat(sdf);
        mapper.setDateFormat(format);
        try {
            return mapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

如果并没有写时间呢?只有一个参数,那么我们把它设置为默认值就好。(不要无谓的重复代码)

public class DateUtils {
    public static String json(Object object){
       return json(object,"yyyy-MM-dd HH:mm:ss");
    }
    public static String json(Object object,String sdf){
        ObjectMapper mapper = new ObjectMapper();
        SimpleDateFormat format = new SimpleDateFormat(sdf);
        mapper.setDateFormat(format);
        try {
            return mapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

我们现在来测试一下

 @RequestMapping("/j6")
    public String j6() throws JsonProcessingException {
        Date date = new Date();
        String date1 = Utils.json(date);

        return date1;
    }
    @RequestMapping("/j7")
    public String js7() throws JsonProcessingException {

        User user = new User(1, "发", 2);

        return Utils.json(user);
    }

奶思,完美运行。

接下来让我们看看fastjson,阿里的。maven里看了下用的没有jackson多

@RequestMapping("/j2")
public String js2() throws JsonProcessingException {
    User user1 = new User(2, "发", 2);
    User user2 = new User(5, "asdsa", 2);
    User user3 = new User(2, "发", 2);
    ArrayList<User> users = new ArrayList<User>();
    users.add(user1);
    users.add(user2);
    users.add(user3);
    String s = JSON.toJSONString(users);
    return s;
}

java对象转换json字符串

JSON.toJSONString(users);

java字符串转java对象

JSON.parseObject(str2,User.class);

Java对象转json对象

(JSONObject) JSON.toJSON(user);

JSON对象转Java对象

JSON.toJavaObject(jsonObject1,User.class);