5_SpringMVC

一. 什么是MVC框架

  • MVC全名是Model View Controller, 是模型(model), 视图(view), 控制器(controller)的缩写, 一种软件设计典范, 用一种业务逻辑、数据、界面显示分离的方法组织代码, 将业务逻辑聚集到一个部件里面, 在改进和个性化定制界面及用户交互的同时, 不需要重新编写业务逻辑

二. SpringMVC是什么

  • SpringMVC是Spring框架的一个模块, 是一个基于MVC的框架

三. SpringMVC的核心

  • DispatcherServlet
  • 前端控制器, 也叫中央控制器, 相关组件都是它来调度

四. SpringMVC的几个组件

  • DispatcherServlet
  • 前端控制器, 也叫中央控制器, 相关组件都是它来调度
  • HandlerMapping
  • 处理器映射器, 根据URL路径映射到不同的Handler
  • HandlerAdapter
  • 处理器适配器, 按照HandlerAdapter的规则去执行Handler
  • Handler
  • 处理器, 由我们自己根据业务开发
  • ViewResolver
  • 视图解析器, 把逻辑视图解析成具体的视图
  • View
  • 一个接口, 它的实现支持不同的视图类型(freeMaker, JSP等)

五. SpringMVC的工作流程

  1. 用户请求旅程第一站是DispatcherServlet
  2. 收到请求后, DispatcherServlet 调用HandlerMapping, 获取对应的Handler
  3. 如果有拦截器一并返回
  4. 拿到Handler后, 提到HandlerAdapter, 通过它来访问Handler, 并执行处理器
  5. 执行Handler的逻辑
  6. Handler会返回一个ModelAndView对象给DispatcherServlet
  7. 将获得到的ModelAndView对象返回给DispatcherServlet
  8. 请求ViewResolver解析视图, 根据逻辑视图名解析成真正的View
  9. 返回View给DispatcherServlet
  10. DispatcherServlet 对View进行渲染视图
  11. DispatcherServlet 响应用户

六. SpringMVC的优点

  1. 具有Spring的特性
  2. 可以支持多种视图(freeMaker, JSP等)
  3. 配置方便
  4. 非侵入
  5. 分层更清晰, 利于团队开发的代码维护, 以及可读性好

  6. Tips: JSP目前很少使用了

七. SpringMVC的工作流程代码

7.1 /web/WEB-INF/web.xml


<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>springmvcservlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>

        <init-param>
            <param-name>contextConfigLocationparam-name>
            <param-value>classpath:springmvc-servlet.xmlparam-value>
        init-param>

        <load-on-startup>1load-on-startup>
    servlet>

    <servlet-mapping>
        <servlet-name>springmvcservlet-name>
        <url-pattern>/url-pattern>
    servlet-mapping>
web-app>

7.2 /resources/springmvc-servlet.xml


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">

        <property name="prefix" value="/WEB-INF/jsp/"/>

        <property name="suffix" value=".jsp"/>
    bean>

    <bean name="/hello" class="com.dz.controller.HelloController"/>
beans>

7.3 /controller/HelloController.java

package com.dz.controller;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloController implements Controller {

    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {

        ModelAndView modelAndView = new ModelAndView();

        String result = "Hello SpringMVC!";

        modelAndView.addObject("msg",result);

        modelAndView.setViewName("hello");
        return modelAndView;
    }
}

7.4 /web/WEb-INF/jsp/hello.jsp

"text/html;charset=UTF-8" language="java" %>

    Title

${msg}

八. 创建SpringMVC项目步骤

8.1 创建Maven项目

  • 先创建好一个Maven项目, 例如 SpringMVC, 创建过程中什么也不用勾选
  • 然后把src目录删除, 之后鼠标右键点击SpringMVC新建Module, 例如 springmvc-01, 我们把SpringMVC当做一个总项目, 下面可以创建很多模块(子项目)
  • 然后在 SpringMVC总项目下的pom.xm中导入依赖和Build(如果所有配置文件都写在resources下就不需要Build), 子项目是共享总项目的pom.xml的, 当然子项目中也可以单独导入自己需要的依赖
<dependencies>
    <dependency>
        <groupId>javax.servletgroupId>
        <artifactId>servlet-apiartifactId>
        <version>2.5version>
    dependency>
    <dependency>
        <groupId>javax.servletgroupId>
        <artifactId>jsp-apiartifactId>
        <version>2.0version>
    dependency>
    <dependency>
        <groupId>javax.servletgroupId>
        <artifactId>jstlartifactId>
        <version>1.2version>
    dependency>
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-webmvcartifactId>
        <version>5.3.5version>
    dependency>
    <dependency>
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <version>4.12version>
        <scope>testscope>
    dependency>
dependencies>
<build>
    <resources>
        <resource>
            <directory>src/main/javadirectory>
            <includes>
                <include>**/*.propertiesinclude>
                <include>**/*.xmlinclude>
            includes>
            <filtering>falsefiltering>
        resource>
        <resource>
            <directory>src/main/resourcesdirectory>
            <includes>
                <include>**/*.propertiesinclude>
                <include>**/*.xmlinclude>
            includes>
            <filtering>falsefiltering>
        resource>
    resources>
build>

8.2 配置web.xml

  • 右键子项目 springmvc-01 > Add Framework Support 然后勾选 Web Application 注意右侧的Versions是否为4.0(要用现阶段的最新版本), 低版本的会出错
  • File > Project Structure > Artifacts > 选择我们当前的子项目 > 在WEB-INF下创建lib目录 > 点击+ > 选择Library Files > 添加所有的jar包 > OK
  • 配置WEB-INF下的 web.xml
  • 注意web.xml版本,要最新版
  • 注册DispatcherServlet
  • 关联SpringMVC的配置文件
  • 启动级别设置为1
  • 映射路径为 / [不要用/*, 会404]

<servlet>
    <servlet-name>springmvcservlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>

    <init-param>
        <param-name>contextConfigLocationparam-name>
        <param-value>classpath:springmvc-servlet.xmlparam-value>
    init-param>

    <load-on-startup>1load-on-startup>
servlet>

<servlet-mapping>
    <servlet-name>springmvcservlet-name>
    <url-pattern>/url-pattern>
servlet-mapping>

8.3 配置springmvc-servlet.xml

  • 在resources下新建 springmvc-servlet.xml文件进行配置

<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:annotation-config/>

    <context:component-scan base-package="com.dz"/>

    <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>

8.4 编写controller

  • src/main/java/com/dz/controller/HelloControler.java
package com.dz.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

public class HelloController {

    public String hello(Model model) {

        model.addAttribute("msg","Hello SpringMVCAnnotation!");

        return "hello";
    }
}

8.5 编写jsp

  • WEB-INF下新建jsp目录, 然后在jsp目录下创建.jsp文件, 例如 *hello.jsp
"text/html;charset=UTF-8" language="java" %>

    Title

${msg}

8.6 测试运行调试

  • 启动Tomcat
  • 注意: 如果我们之前运行过其他子项目时, 别忘了在Deploment中将上一个子项目删除掉, 换上我们本次需要运行的项目
  • Edit > Deployment > 减号去掉之前的项目 > 然后加号选择我们本次运行的项目
  • 任何时候出现 1 字节的 UTF-8 序列的字节 1 无效 的错误请在总项目的pom.xml中配置以下编码格式
<properties>
    <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>

九. 请求与响应

9.1 RequestMapping

  • @RequestMapping注解用于映射url到控制器类或者一个特定的处理程序方法. 可用于 类或方法上, 用于类上, 表示类中所有响应请求的方法都是以该地址作为父路径
  • localhost:8080/admin/t0
package com.dz.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

public class ControllerTest3 {

    public String test3(Model model) {
        String result = "Java 太棒啦!";
        model.addAttribute("msg",result);

        return "admin/test0";
    }
}

9.2 Restful风格

  • 概念
  • Restful就是一个资源定位及资源操作的风格. 不是标准也不是协议, 只是一种风格, 基于这个风格设计的软件可以更简洁, 更有层次, 更易于实现缓存等机制
  • 功能
  • 资源: 互联网所有事物都可以被抽象为资源
  • 资源操作: 使用POST, DELETE, PUT, GET, 使用不同的方法对资源进行操作
  • 分别对应 添加 删除 修改 查询
  • 传统方式操作资源: 通过不同的参数来实现不同的效果! 方法单一,post和get
  • http://127.0.0.1/item/queryItem.action?id=1 查询,GET
  • http://127.0.0.1/item/saveItem.action 新增,POST
  • http://127.0.0.1/item/updateItem.action 更新,PUT
  • http://127.0.0.1/item/deleteItem.action?id=1 删除,GET或POST
  • 使用Restful操作资源: 可以通过不同的请求方式来实现不同的效果, 如下: 请求地址一样, 但是功能可以不同
  • http://127.0.0.1/item/1 查询,GET
  • http://127.0.0.1/item 新增,POST
  • http://127.0.0.1/item 更新,PUT
  • http://127.0.0.1/item/1 删除,DELETE
  • 在SpringMVC中可以使用 @PathVariable注解, 让方法参数的值对应绑定到一个URL模板变量上
  • @RequestMapping注解能够处理HTTP请求的方法,比如GET, PUT, POST, DELETE 以及 PATCH
  • 所有的地址栏请求默认都会是HTTP GET类型的
  • 方法级别的注解变体有如下几个: 组合注解
package com.dz.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

public class RestfulController {

    public String test4( int a,  String b, Model model) {
        String result = a + b;
        model.addAttribute("msg", "result1=" + result);

        return "test";
    }

    public String test5( int a,  String b, Model model) {
        String result = a + b;
        model.addAttribute("msg", "result2=" + result);

        return "test";
    }

}

9.3 SpringMVC结果跳转方式

9.3.1 ModelAndView
  • 设置ModelAndView对象, 根据view的名称, 和视图解析器跳到指定的页面
  • 页面: [视图解析器前缀] + viewName + [视图解析器后缀]

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
      id="internalResourceViewResolver">

    <property name="prefix" value="/WEB-INF/jsp/"/>

    <property name="suffix" value=".jsp"/>
bean>
  • 对应的controller类

public class ControllerTest1 implements Controller {

    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {

        ModelAndView modelAndView = new ModelAndView();
        String result = "学习SpringMVC!";
        modelAndView.addObject("msg",result);
        modelAndView.setViewName("test");
        return modelAndView;
    }
}
  • 使用注解时的controller
package com.dz.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

public class HelloController {

    public String hello(Model model) {

        model.addAttribute("msg","Hello SpringMVCAnnotation!");

        return "hello";
    }
}
9.3.2 通过SpringMVC实现转发和重定向
  • 无需视图解析器, 测试前把视图解析器注释掉
package com.dz.controller;

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

public class ModelTest1 {

    public String test1() {

        return "/index.jsp";
    }

    public String test2() {

        return "forward:/index.jsp";
    }

    public String test3() {

        return "redirect:/index.jsp";
    }
}
  • 实际使用时,
  • 转发:
    • return “test”;
    • 或者 return “forward:test”;
  • 重定向:
    • return “redirect:test”;
  • 注意: test 要在WEB-INF下

9.4 接收请求参数及数据回显

  • 接收请求参数
  • 接收前端用户传递的参数, 判断参数的名字, 假设名字直接在方法上, 可以直接使用
  • 假设前端传递的是一个对象User, 匹配User对象中的字段名, 如果名字一致就匹配到, 反之为null
  • 请确保前端传递的 请求参数 和后端方法的 参数名 一致
    • @RequestParam(“username”) 代表只能接收前端的请求参数为username
package com.dz.controller;

import com.dz.poji.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

public class UserController {

    public String test( String name, Model model) {

        System.out.println("接收到的参数名是: " + name);

        model.addAttribute("msg",name);

        return "test";
    }

    public String test2(User user) {
        System.out.println(user);
        return "test";
    }

}

数据回显

  • Model 只有几个方法适合用于存储数据, 简化了新手对Model对象的操作和理解
  • ModelMap 继承了LinkedMap 除了实现了自身的一些方法, 同样继承了LinkedMap的方法和特性
  • ModelAndView 可以在存储数据的同时, 进行设置返回的逻辑视图,进行控制展示层的跳转

9.5 乱码问题

9.5.1 自己写一个过滤器
package com.dz.filter;

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

public class EncodingFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

}
  • 然后去web.xml里配置
<filter>
    <filter-name>EncodingFilterfilter-name>
    <filter-class>com.dz.filter.EncodingFilterfilter-class>
filter>
<filter-mapping>
    <filter-name>EncodingFilterfilter-name>
    <url-pattern>/*url-pattern>
filter-mapping>
9.5.2 使用SpringMVC的过滤器
  • 直接在web.xml里配置以下信息
<filter>
    <filter-name>encodingfilter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
    <init-param>
        <param-name>encodingparam-name>
        <param-value>utf-8param-value>
    init-param>
filter>
<filter-mapping>
    <filter-name>encodingfilter-name>
    <url-pattern>/*url-pattern>
filter-mapping>

9.6 JSON

9.6.1 概念
  • 前后端分离时代
  • 后端部署后端, 提供接口, 提供数据
  • 前端独立部署, 负责渲染后端的数据
  • 所以前后端统一使用 JSON进行数据交换
  • JSON(JavaScript Object Notation, JS对象标记) 是一种轻量级的 数据交换格式 , 目前使用特别广泛
  • 采用完全独立于编程语言的 文本格式 来存储和表示数据
  • 简洁和清晰的层次结构使得JSON成为理想的数据交换语言
  • 易于人阅读和编写, 同时也易于机器解析和生成, 并有效地提升网络传输效率
  • 在 JavaScript 语言中, 一切都是对象. 因此,任何JavaScript 支持的类型都可以通过 JSON 来表示, 例如字符串, 数字, 对象, 数组等, 其要求的语法格式为:
  • 对象表示为键值对, 数据由逗号分隔
  • 花括号保存对象
  • 方括号保存数组
  • JSON键值对 是用来保存 JavaScript 对象的一种方式, 和 JavaScript 对象的写法也大同小异, 键值对组合中的键名写在前面并用双引号 “” 包裹, 使用冒号: 分隔, 然后紧接着写值
{"name": "张三"}
{"age": "18"}
{"sex": "男"}
9.6.2 JSON和JavaScript
  • JSONJavaScript(以下简称 JS) 对象的字符串表示法, 它使用文本表示一个JS对象的信息, 本质是一个字符串
var obj = {name: "张三", age: 18, sex: "男"};
var json = '{"name":"张三","age":18,"sex":"男"}';
  • JSON 和 JS 对象转换
  • JSON字符串转为JS对象, 使用 JSON.parse() 方法
  • JS对象转为 JSON字符串, 使用 JSON.stringify() 方法
<script type="text/javascript">

    var user = {
        name:"张三",
        age:18,
        sex:"男"
        };

    var json = JSON.stringify(user);
    console.log(json)

    console.log("==============")

    var obj = JSON.parse(json);
    console.log(obj);
script>
9.6.3 jackson [重点]
  • Java平台的JSON库, 用来序列化和反序列化 json 的 Java 的开源框架
  • 使用前先导入以下依赖

<dependency>
    <groupId>com.fasterxml.jackson.coregroupId>
    <artifactId>jackson-databindartifactId>
    <version>2.12.3version>
dependency>

<dependency>
    <groupId>org.projectlombokgroupId>
    <artifactId>lombokartifactId>
    <version>1.18.16version>
    <scope>providedscope>
dependency>
  • @ResponseBody(用在方法上): 表示此方法不走视图解析器, 会直接返回一个字符串, @ResponseBody+@Controller=@RestController
  • @RestController(用在类上): 表示此类下的所有方法只会返回字符串
  • ObjectMapper: 调用writeValueAsString方法,把对象转为JSON格式
package com.dz.controller;

import com.dz.pojo.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

public class UserController {

    public String json1() throws JsonProcessingException {

        ObjectMapper mapper = new ObjectMapper();

        User user = new User("张三",11,true);

        String str = mapper.writeValueAsString(user);
        return str;

    }
}
  • 如果出现乱码我们需要设置它的编码格式为utf-8, 以及返回类型,就是下面这句
9.6.4 统一解决JSON乱码问题 [重点]
  • 在springmvc-servlet.xml中做以下配置

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <constructor-arg value="UTF-8"/>
        bean>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                    <property name="failOnEmptyBeans" value="false"/>
                bean>
            property>
        bean>
    mvc:message-converters>
mvc:annotation-driven>
9.6.5 返回前端一个JSON集合

public String json2() throws JsonProcessingException {

    ObjectMapper mapper = new ObjectMapper();

    List userList = new ArrayList<>();
    User user1 = new User("张三1",11,true);
    User user2 = new User("张三2",11,true);
    User user3 = new User("张三3",11,true);
    User user4 = new User("张三4",11,true);

    userList.add(user1);
    userList.add(user2);
    userList.add(user3);
    userList.add(user4);

    String str = mapper.writeValueAsString(userList);

    return str;
}
9.6.6 返回前端日期格式的JSON

方法一: 因为ObjectMapper解析Date后的默认格式为: Timestamp: 时间戳, 所以我们先使用SimpleDateFormat把日期转为字符串,再被ObjectMapper解析


public String json3() throws JsonProcessingException {

    ObjectMapper mapper = new ObjectMapper();

    Date date = new Date();

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String s = sdf.format(date);

    return mapper.writeValueAsString(s);
}

方法二 关闭ObjectMapper解析Date后默认的时间戳格式, 改用我们自定义的日期格式


public String json4() 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);
}
9.6.7 JSON工具类 [重点]
package com.dz.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.text.SimpleDateFormat;

public class JsonUtils {

    public static String getJson(Object object) {
        return getJson(object, "yyyy-MM-dd HH:mm:ss");
    }

    public static String getJson(Object object, String dateFormat) {
        ObjectMapper mapper = new ObjectMapper();

        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        mapper.setDateFormat(sdf);

        try {
            return mapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        return null;
    }
}

public String json5() throws JsonProcessingException {

    return JsonUtils.getJson(new Date());
}
  • 使用工具类后给前端返回字符串变得就很简单,
  • 提供想要被解析成JSON字符串的对象
  • 使用JSON工具类解析并返回JSON字符串
  • *最后也是最重要的一点就是可以使用注解@JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”), 在日期属性上写上注解即可, 十分方便
9.6.8 fastjson [重点]
  • fastjson是由alibaba开源的一套json处理器。与其他json处理器(如Gson,Jackson等)和其他的Java对象序列化反序列化方式相比,有比较明显的性能优势
  • 使用前先导入以下依赖

<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>fastjsonartifactId>
    <version>1.2.75version>
dependency>
  • 导入依赖后直接用就行, JSON.toJSONString(对象)

public String json6() throws JsonProcessingException {

    List userList = new ArrayList<>();
    User user1 = new User("张三1",11,true);
    User user2 = new User("张三2",11,true);
    User user3 = new User("张三3",11,true);
    User user4 = new User("张三4",11,true);

    userList.add(user1);
    userList.add(user2);
    userList.add(user3);
    userList.add(user4);

    return JSON.toJSONString(userList);
}

9.7 jQuery

  • *jQuery 库可以通过一行简单的标记被添加到网页中
9.7.1 jQuery库特性
  • jQuery 是一个 JavaScript 函数库
  • jQuery 库包含以下特性:
  • HTML 元素选取
  • HTML 元素操作
  • CSS 操作
  • HTML 事件函数
  • JavaScript 特效和动画
  • HTML DOM 遍历和修改
  • AJAX
  • Utilities
9.7.2 下载和使用
  • 下载
  • 使用前请先下载jquery-3.5.1.js(版本可自己选择), 然后web下创建/statics/js 放在此目录下(目录名自己定)
  • jquery下载地址:https://www.jq22.com/jquery-info122
  • 使用
  • jQuery 库位于一个 JavaScript 文件中,其中包含了所有的 jQuery 函数, 可以通过下面的标记把 jQuery 添加到网页中:

"text/javascript"</span> src=<span class="hljs-string">"jquery.js"</span>>

  • 库的替代
  • 如果您不愿意在自己的计算机上存放 jQuery 库,那么可以从 Google 或 Microsoft 加载 CDN jQuery 核心文件。
  • 使用 Google 的CDN

"text/javascript"</span> src=<span class="hljs-string">"http://ajax.googleapis.com/ajax/libs
/jquery/1.4.0/jquery.min.js"</span>>

  • 使用 Microsoft 的 CDN

"text/javascript"</span> src=<span class="hljs-string">"http://ajax.microsoft.com/ajax/jquery
/jquery-1.4.min.js"</span>>

9.8 AJAX

9.8.1 简介
  • AJAX = Asynchronous JavaScript And XML(异步 JavaScript 及 XML)
    AJAX 是 Asynchronous JavaScript And XML 的首字母缩写。
  • AJAX 并不是一种新的编程语言,而仅仅是一种新的技术,它可以创建更好、更快且交互性更强的 web 应用程序。
  • AJAX 使用 JavaScript 在 web 浏览器与 web 服务器之间来发送和接收数据。
  • 通过在幕后与 web 服务器交换数据, 而不是每当用户作出改变时重载整个 web 页面,AJAX 技术可以使网页更迅速地响应
  • AJAX 基于以下开放的标准:
  • JavaScript
  • XML
  • HTML
  • CSS
  • 在 AJAX 中使用的开放标准被良好地定义,并得到所有主要浏览器的支持。AJAX 应用程序独立于浏览器和平台。(可以说,它是一种跨平台跨浏览器的技术)
  • *使用AJAX技术之前先把JQuery库引用到页面中
9.8.2 AJAX初体验
  • controller

    public void a1(String name, HttpServletResponse response) throws IOException {
        System.out.println("a1:param=>"+name);
        if ("dz".equals(name)) {
            response.getWriter().println("true");
        }else {
            response.getWriter().println("false");
        }
    }
  • html

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>iframe测试title>

    <script>
        function go() {
            var url = document.getElementById("url").value;
            document.getElementById("iframe1").src=url;
        }
    script>
head>
<body>

<div>
    <p>请输入地址: p>
    <p>
        <input type="text" id="url" value="https://space.bilibili.com">
        <input type="button" value="提交" onclick="go()">
    p>
div>

<div>
    <iframe id="iframe1" style="width: 100%;height: 500px">iframe>
div>

body>
html>
9.8.3 AJAX异步加载数据
  • controller

public List a2() {
    List userList = new ArrayList<>();

    userList.add(new User("dz1啦啦啦",1,"男"));
    userList.add(new User("dz2啦啦啦",1,"女"));
    userList.add(new User("dz3啦啦啦",1,"男"));

    return userList;
}
  • jsp
"text/html;charset=UTF-8" language="java" %>

    Title
    "${pageContext.request.contextPath}/statics/js/jquery-3.5.1.js"</span>>

        $(function () {
            $(<span class="hljs-string">"#btn"</span>).click(function () {

                $.post(<span class="hljs-string">"${pageContext.request.contextPath}/a2"</span>,function (data) {

                    <span class="hljs-keyword">var</span> html=<span class="hljs-string">""</span>;
                    <span class="hljs-keyword">for</span> (<span class="hljs-type">let</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">0</span>; i < data.length; i++) {
                        html += <span class="hljs-string">"<tr>"</span> +
                            <span class="hljs-string">"<td>"</span> + data[i].name + <span class="hljs-string">"</td>"</span> +
                            <span class="hljs-string">"<td>"</span> + data[i].age + <span class="hljs-string">"</td>"</span> +
                            <span class="hljs-string">"<td>"</span> + data[i].sex + <span class="hljs-string">"</td>"</span> +
                            <span class="hljs-string">"</tr>"</span>
                    }
                    $(<span class="hljs-string">"#content"</span>).html(html);
                });
            });
        });

"button" value="加载数据" id="btn">

        姓名
        年龄
        性别

    "content">

9.7.3 AJAX验证用户名密码
  • controller

public String a3(String name,String pwd) {
    String msg = "";
    if (name != null) {

        if ("admin".equals(name)) {
            msg = "ok";
        }else {
            msg = "用户名有误";
        }
    }
    if (pwd != null) {

        if ("123456".equals(pwd)) {
            msg = "ok";
        }else {
            msg = "密码有误";
        }
    }
    return msg;
}
  • jsp
"text/html;charset=UTF-8" language="java" %>

    登陆

    "${pageContext.request.contextPath}/statics/js/jquery-3.5.1.js"</span>>

        function <span class="hljs-title function_">a1</span><span class="hljs-params">()</span> {
            $.post({
                url: <span class="hljs-string">"${pageContext.request.contextPath}/a3"</span>,
                data: {<span class="hljs-string">"name"</span>:$(<span class="hljs-string">"#name"</span>).val()},
                success: function (data) {
                    <span class="hljs-keyword">if</span> (data.toString()===<span class="hljs-string">'ok'</span>) {
                        $(<span class="hljs-string">"#userInfo"</span>).css(<span class="hljs-string">"color"</span>,<span class="hljs-string">"green"</span>);
                    }<span class="hljs-keyword">else</span> {
                        $(<span class="hljs-string">"#userInfo"</span>).css(<span class="hljs-string">"color"</span>,<span class="hljs-string">"red"</span>);
                    }
                    $(<span class="hljs-string">"#userInfo"</span>).html(data);
                }
            })
        }
        function <span class="hljs-title function_">a2</span><span class="hljs-params">()</span> {
            $.post({
                url: <span class="hljs-string">"${pageContext.request.contextPath}/a3"</span>,
                data: {<span class="hljs-string">"pwd"</span>:$(<span class="hljs-string">"#pwd"</span>).val()},
                success: function (data) {
                    <span class="hljs-keyword">if</span> (data.toString()===<span class="hljs-string">'ok'</span>) {
                        $(<span class="hljs-string">"#pwdInfo"</span>).css(<span class="hljs-string">"color"</span>,<span class="hljs-string">"green"</span>);
                    }<span class="hljs-keyword">else</span> {
                        $(<span class="hljs-string">"#pwdInfo"</span>).css(<span class="hljs-string">"color"</span>,<span class="hljs-string">"red"</span>);
                    }
                    $(<span class="hljs-string">"#pwdInfo"</span>).html(data);
                }
            })
        }

    用户名: "text" id="name" onblur="a1()">
    "userInfo">

    密码: "text" id="pwd" onblur="a2()">
    "pwdInfo">

  • 如出现JSON乱码问题, 请看 9.6.4 小节

9.9 SpringMVC 拦截器

  • SpringMVC的 处理器拦截器 类似于Servlet开发中的过滤器Filter, 用于对处理器进行预处理和后处理, 开发者可以自定义一些拦截器来实现特定的功能
  • 过滤器与拦截器的区别
  • 拦截器是AOP思想的具体应用
  • 过滤器
  • servlet规范中的一部分, 任何java web 工程都可以使用
  • 在 url-pattern 中配置了 /* 之后, 可以对所有要访问的资源进行拦截
  • 拦截器
  • 拦截器是SpringMVC框架自己的, 只有使用了SpringMVC框架的工程才能使用
  • 拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/images/js是不会进行拦截的
9.9.1 自定义拦截器
  • 必须实现 HandlerInterceptor 接口
  • 步骤

  • 新建一个Module springmvc-07-interceptor 添加web支持

  • 配置web.xml 和 springmvc-servlet.xml 文件
  • 编写一个拦截器
package com.dz.config;

import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("======处理前======");
        return true;
    }
}
  • 然后去springmvc-servlet.xml中做以下配置,
  • /** 代表拦截所有访问controller的请求

<mvc:interceptors>
    <mvc:interceptor>

        <mvc:mapping path="/**"/>
        <bean class="com.dz.config.MyInterceptor"/>
    mvc:interceptor>
mvc:interceptors>
9.9.2 拦截器实现登陆判断验证
  • springmvc-servlet.xml中做以下配置,
<mvc:interceptors>
    <mvc:interceptor>

        <mvc:mapping path="/user/**"/>
        <bean class="com.dz.config.LoginInterceptor"/>
    mvc:interceptor>
mvc:interceptors>
  • LoginController.java
package com.dz.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpSession;

public class LoginController {

    public String toMain() {
        return "main";
    }

    public String toLogin() {
        return "login";
    }

    public String login(HttpSession session, String username, String password, Model model) {

        session.setAttribute("userLoginInfo",username);
        model.addAttribute("userLoginInfo",username);
        return "main";
    }

    public String logout(HttpSession session) {

        session.removeAttribute("userLoginInfo");

        return "redirect:main";
    }
}

  • LoginInterceptor.java
package com.dz.config;

import org.springframework.web.servlet.HandlerInterceptor;

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

public class LoginInterceptor implements HandlerInterceptor {

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();

        if (request.getRequestURI().contains("toLogin")) {
            return true;
        }

        if (request.getRequestURI().contains("login")) {
            return true;
        }

        if (session.getAttribute("userLoginInfo") != null){
            return true;
        }

        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);

        return false;
    }
}
  • index.jsp
"text/html;charset=UTF-8" language="java" %>

    $Title$

  "${pageContext.request.contextPath}/user/toLogin">登陆页面

  "${pageContext.request.contextPath}/user/toMain">首页

  • login.jsp
"text/html;charset=UTF-8" language="java" %>

    登陆页面

登陆页面
"${pageContext.request.contextPath}/user/login" method="post">
    用户名: "text" name="username">
    密码: "text" name="password">
    "submit" value="提交">

  • main.jsp
"text/html;charset=UTF-8" language="java" %>

    Title

首页

${userLoginInfo}

    "${pageContext.request.contextPath}/user/logout">退出登陆

9.10 SpringMVC文件上传和下载

  • 文件上传是项目开发中最常见的功能之一, SpringMVC上下文中默认没有装配MultipartResolver, 因此默认情况下不能处理文件上传工作, 如果想要使用Spring的文件上传功能, 则需 在上下文中配置 MultipartResolver
  • 前端表单要求:: 为了能上传文件, 必须将表单的 method设置为post, 并将 enctype设置为 multipart/form-data. 只有在这样的情况下, 浏览器才会把用户选择的文件以二进制数据发送给服务器
9.10.1 导入相关依赖

<dependency>
    <groupId>commons-fileuploadgroupId>
    <artifactId>commons-fileuploadartifactId>
    <version>1.4version>
dependency>

<dependency>
    <groupId>javax.servletgroupId>
    <artifactId>javax.servlet-apiartifactId>
    <version>4.0.1version>
    <scope>providedscope>
dependency>
9.10.2 配置springmvc.xml

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

        <property name="defaultEncoding" value="utf-8"/>

        <property name="maxUploadSize" value="10485760"/>
        <property name="maxInMemorySize" value="40960"/>
    bean>
9.10.3 index.jsp
"text/html;charset=UTF-8" language="java" %>

    文件上传

  "${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post">
    "file" name="file">
    "submit" value="upload">

  "${pageContext.request.contextPath}/download">下载图片

9.10.4 FileController.java
package com.dz.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;

public class FileController {

    public String fileUpload( CommonsMultipartFile file, HttpServletRequest request) throws IOException, ServletException {

        String uploadFilename = file.getOriginalFilename();

        if ("".equals(uploadFilename)) {
            return "redirect:/index.jsp";
        }
        System.out.println("上传文件名: " + uploadFilename);

        String path = request.getServletContext().getRealPath("/WEB-INF/upload");

        File realpath = new File(path);
        if (!realpath.exists()) {
            realpath.mkdirs();
        }
        System.out.println("上传文件保存地址: " + realpath);

        InputStream is = file.getInputStream();

        OutputStream os = new FileOutputStream(new File(realpath, uploadFilename));

        int len = 0;
        byte[] buffer = new byte[1024];
        while ((len=is.read(buffer))!=-1){
            os.write(buffer,0,len);
            os.flush();
        }
        os.close();
        is.close();

        return "redirect:index";

    }

    public String fileDownload(HttpServletRequest request, HttpServletResponse response) throws IOException {

        String path = request.getServletContext().getRealPath("/WEB-INF/upload");
        String filename = "butterfly.jpg";

        response.reset();
        response.setCharacterEncoding("UTF-8");
        response.setContentType("multipart/form-data");

        response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(filename,"UTF-8"));

        File file = new File(path, filename);

        InputStream is = new FileInputStream(file);

        OutputStream os = response.getOutputStream();
        byte[] buffer = new byte[1024*1024*100];
        int len = 0;
        while ((len=is.read(buffer)) != -1) {
            os.write(buffer,0,len);
        }

        is.close();
        os.close();

        return "redirect";
    }
}

Original: https://www.cnblogs.com/qimu666/p/16565690.html
Author: 柒木木木
Title: 5_SpringMVC

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/598774/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • JavaScript进阶内容——jQuery

    JavaScript进阶内容——jQuery 我们在前面的文章中已经掌握了JavaScript的全部内容,现在让我们了解一下JavaScript库 这篇文章主要是为了为大家大致讲解…

    数据库 2023年6月14日
    0101
  • docker部署redis集群

    docker部署redis集群 1.0 安装环境 1.1 安装Centos7 Docker官方建议在Ubuntu中安装,因为Docker是基于Ubuntu发布的,而且一般Docke…

    数据库 2023年6月9日
    088
  • Linux定时任务调度

    任务调度是指系统在某个时间执行特定的命令或程序,任务调度主要有两种,第一种是系统工作,需要周而复始的执行,比如病毒扫描。第二种是个人用户工作,用户需要在某个特定的事件执行某些程序,…

    数据库 2023年6月16日
    092
  • MySQL 笔记

    情景一数据库概述基本术语DB : 数据库 ( Database )它是根据数据结构组织、存储和管理数据的仓库。它被视为电子档案柜,用户可以对文件中的数据进行添加、删除、修改、查找等…

    数据库 2023年5月24日
    088
  • centos8 安装python

    镜像:CentOS Linux release 8.5.0-13 python下载地址:Python Source Releases | Python.org 选择所需要的版本,我…

    数据库 2023年6月11日
    0109
  • MySQL主从复制

    一、概述 主从复制是指将主数据库(Master)的DDL和DML操作通过二进制日志传到从库(Slave)服务器中,然后在从库上对这些日志重新执行(也叫重做),从而使得从库和主库的数…

    数据库 2023年5月24日
    0107
  • 分库分表真的适合你的系统吗?聊聊分库分表和NewSQL如何选择

    曾几何时,”并发高就分库,数据大就分表”已经成了处理 MySQL 数据增长问题的圣经。 面试官爱问,博主爱写,考生爱背诵,似乎形成了一个闭环。 [En] I…

    数据库 2023年5月24日
    0112
  • 一致性hash算法

    背景 当我们的业务系统大到一定程度的时候,一台缓存服务器显然不能满足需求,需要使用多台缓存服务器。然后缓存服务器具体一定的用户粘性属性,如何设计缓存服务器使其命中率提高,并具有伸缩…

    数据库 2023年6月9日
    086
  • cobbler部署

    cobbler cobbler 一、cobbler简介 二、cobbler对应关系 三、cobbler工作原理 cobbler部署 进行测试 web界面自动安装 一、cobbler…

    数据库 2023年6月14日
    084
  • SQL Server2019安装

    检查.NET 环境 打开控制面板下面的程序,选择 &#x542F;&#x7528;&#x6216;&#x5173;&#x95ED; Wind…

    数据库 2023年6月6日
    098
  • Vue(十一)—key特殊attribute

    预期: number | string | boolean (2.4.2 &#x65B0;&#x589E;) | symbol (2.5.12 &#x65B…

    数据库 2023年6月16日
    085
  • javaWeb知识点大集合!!!

    pom文件: 4.0.0 org.example javaweb_maven 1.0-SNAPSHOT war UTF-8 1.7 1.7 com.github.pagehelpe…

    数据库 2023年6月16日
    086
  • Mysql查询优化

    mysq查询l优化 指标:执行时间 检查的行数 返回的行数 explain关键字 — 实际SQL,查找用户名为Jefabc的员工 select * from emp where …

    数据库 2023年5月24日
    0117
  • MySQL隐式转换的坑

    MySQL以以下规则描述比较操作如何进行转换: 两个参数至少有一个是 NULL 时,比较的结果也是 NULL,例外是使用 实际使用中经研究发现字符串和数字比较时,优先把字符串转换为…

    数据库 2023年6月9日
    074
  • mysql开启二进制日志

    打开xhell进入系统 进入mysql配置文件目录 执行 cd /etc/mysql 首先找到my.cnf这个配置文件,然后使用vim进入文件编辑 放开我标记的地方。 注意我标记的…

    数据库 2023年6月6日
    0121
  • 页面静态化

    网站的首页频繁被访问,为了提升访问速度,除了我们之前已经学过的使用缓存技术外,还可以使用页面静态化技术。 页面静态化即将动态渲染生成的页面结果保存成html文件,放到静态文件服务器…

    数据库 2023年6月14日
    082
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球