6

时间:2018年04月19日星期四
说明:本文部分内容均来自慕课网。@慕课网:https://www.imooc.com
教学源码:https://github.com/zccodere/s...
学习源码:https://github.com/zccodere/s...

第一章:基础介绍

1-1 简介说明

SpringBoot简介

  • 微框架,与Spring4一起诞生,比如@RestController
  • 可以快速上手,整合了一些子项目(开源框架或者第三方开源库)
  • 可以依赖很少的配置就可以十分快速的搭建并且运行项目

SpringBoot特点

  • Spring全家桶的一员:基于Spring,使开发者快速入门,门槛很低
  • SpringBoot可以创建独立运行的应用而不依赖于容器
  • 不需要打成war包,可以放入tomcat中直接运行
  • 提供maven极简配置,缺点就是会引入很多不需要的包
  • 根据项目来依赖,从而配置Spring,需要什么引用什么
  • 提供可视化的相关功能,方便监控,比如性能、应用的健康程度等
  • 简化配置,不用再看过多的xml,使用注解进行配置
  • 为微服务SpringCloud铺路,SpringBoot可以整合很多框架来构建微服务,比如Dubbo、Thrift等

SpringBoot使用场景

  • 有Spring的地方都可以使用SpringBoot
  • JavaWeb项目:JavaEE项目等
  • 微服务:SpringCloud微服务开发的基础

1-2 首个项目

Spring官方提供的项目骨架生成地址

代码编写

1.创建名为boot-start的maven项目pom文件如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.myimooc</groupId>
    <artifactId>boot-start</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>boot-start</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--spring boot 热启动模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <!--optional = true,表示依赖不会传递,即该项目依赖 devtools;如果有其它项目依赖该项目,则其它项目不会自动依赖 devtools-->
            <optional>true</optional>
        </dependency>

        <!--spring boot 配置文件加载模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>

        <!--引入 Freemarker 模版引擎依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <!--引入 Thymeleaf 模版引擎依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!--<dependency>-->
            <!--<groupId>com.alibaba</groupId>-->
            <!--<artifactId>druid</artifactId>-->
            <!--<version>1.1.0</version>-->
        <!--</dependency>-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.41</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>
        <!--mapper-->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>1.2.4</version>
        </dependency>
        <!--pagehelper-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.3</version>
        </dependency>
        <!--<dependency>-->
            <!--<groupId>com.alibaba</groupId>-->
            <!--<artifactId>druid-spring-boot-starter</artifactId>-->
            <!--<version>1.1.0</version>-->
        <!--</dependency>-->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.2</version>
            <scope>compile</scope>
            <optional>true</optional>
        </dependency>

        <!--引入redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.5.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

2.编写BootStartApplication类

package com.myimooc.boot.start;

import org.n3r.idworker.Sid;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import tk.mybatis.spring.annotation.MapperScan;

/**
 * <br>
 * 标题: 启动类<br>
 * 描述: 首个SpringBoot项目<br>
 * 使用 @EnableScheduling 开启支持定时任务
 * 使用 @EnableAsync 开启异步执行程序
 * @author zc
 * @date 2018/04/19
 */
@SpringBootApplication
@MapperScan("com.myimooc.boot.start.dao.mapper")
@EnableScheduling
@EnableAsync
public class BootStartApplication {

    public static void main(String[] args) {
        SpringApplication.run(BootStartApplication.class, args);
    }

    @Bean
    public Sid sid() {
        return new Sid();
    }
}

3.编写HelloController类

package com.myimooc.boot.start.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * <br>
 * 标题: 基于REST的Controller<br>
 * 描述: 返直接返回方法的响应内容<br>
 *
 * @author zc
 * @date 2018/04/19
 */
@RestController
public class HelloController {

    @GetMapping("/hello")
    public Object hello(){
        return "Hello SpringBoot!";
    }

}

然后启动BootStartApplication,访问http://localhost:8080/hello

第二章:常用开发

2-1 响应对象

通常一个应用都会有一个统一的响应对象,用于封装响应状态、响应消息、响应数据等,并提供一些常用静态方法

代码编写

1.编写JsonResult类

package com.myimooc.boot.start.domain;

import java.io.Serializable;

/**
 * <br>
 * 标题: 自定义JSON响应数据结构<br>
 * 描述: 统一请求响应返回的格式<br>
 * 200 成功
 * 500 错误,错误信息在msg字段中
 * 501 Bean验证错误信息,以map返回
 * 502 拦截器拦截到用户token出错
 * 555:抛出异常信息
 * @author zc
 * @date 2018/04/19
 */
public class JsonResult implements Serializable{

    private static final long serialVersionUID = 4997293587553904193L;
    /**
     * 响应状态
     */
    private Integer status;
    /**
     * 响应消息
     */
    private String msg;
    /**
     * 响应数据
     */
    private Object data;

    public static JsonResult build(Integer status,String msg,Object data){
        return new JsonResult(status,msg,data);
    }
    public static JsonResult ok(Object data){
        return new JsonResult(200,"ok",data);
    }
    public static JsonResult ok(){
        return JsonResult.ok(null);
    }
    public static JsonResult errMsg(String msg){
        return new JsonResult(500,msg,null);
    }
    public static JsonResult errMap(Object data){
        return new JsonResult(501,"error",data);
    }
    public static JsonResult errTokenMsg(String msg){
        return new JsonResult(502,msg,null);
    }
    public static JsonResult errException(String msg){
        return new JsonResult(555,msg,null);
    }

    public JsonResult() {
    }

    public JsonResult(Integer status, String msg, Object data) {
        this.status = status;
        this.msg = msg;
        this.data = data;
    }

    @Override
    public String toString() {
        return "JsonResult{" +
                "status=" + status +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                '}';
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

2.编写User类

package com.myimooc.boot.start.domain;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;

import java.io.Serializable;
import java.util.Date;

/**
 * <br>
 * 标题: POJO类<br>
 * 描述: 用户信息<br>
 *
 * @author zc
 * @date 2018/04/19
 */
public class User implements Serializable {

    private static final long serialVersionUID = 7332961063564924222L;
    /**
     * 名称
     */
    private String name;
    /**
     * 密码,使用 @JsonIgnore 注解,在序列化为 JSON 时,忽略该字段
     */
    @JsonIgnore
    private String password;
    /**
     * 年龄
     */
    private Integer age;
    /**
     * 生日,使用 @JsonFormat 注解,在序列化为 JSON 时,使用 pattern 属性指定的值格式化日期时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd",locale = "zh",timezone = "GMT+8")
    private Date birthday;
    /**
     * 描述,使用 @JsonInclude 注解,在序列化为 JSON 时,当字段为 null 时,则忽略该字段
     */
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String note;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                ", note='" + note + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }
}

3.编写UserController类

package com.myimooc.boot.start.controller;

import com.myimooc.boot.start.domain.JsonResult;
import com.myimooc.boot.start.domain.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

/**
 * <br>
 * 标题: 使用Controller<br>
 * 描述: 返回JSON数据<br>
 *
 * @author zc
 * @date 2018/04/19
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @GetMapping("/getUser")
    public User getUser(){
        User user = new User();
        user.setName("myImooc2");
        user.setPassword("myImooc");
        user.setAge(22);
        user.setBirthday(new Date());
        user.setNote("Hello");
        return user;
    }

    @GetMapping("/getUserJson")
    public JsonResult getUserJson(){
        User user = new User();
        user.setName("myImooc2");
        user.setPassword("myImooc");
        user.setAge(22);
        user.setBirthday(new Date());
        user.setNote("Hello");
        return JsonResult.ok(user);
    }

}

2-2 配置文件

资源文件中的属性配置与映射到实体类,即加载配置文件到实体类中

代码编写

1.编写resource.properties

com.imooc.opensource.name=imooc
com.imooc.opensource.website=www.imooc.com
com.imooc.opensource.language=java

2.编写Resource类

package com.myimooc.boot.start.domain;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

/**
 * <br>
 * 标题: 配置属性实体类<br>
 * 描述: 从配置文件中获取属性值<br>
 *
 * @author zc
 * @date 2018/04/25
 */
@Configuration
@ConfigurationProperties(prefix = "com.imooc.opensource")
@PropertySource(value = "classpath:resource.properties")
public class Resource {

    private String name;

    private String website;

    private String language;

    @Override
    public String toString() {
        return "Resource{" +
                "name='" + name + '\'' +
                ", website='" + website + '\'' +
                ", language='" + language + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getWebsite() {
        return website;
    }

    public void setWebsite(String website) {
        this.website = website;
    }

    public String getLanguage() {
        return language;
    }

    public void setLanguage(String language) {
        this.language = language;
    }
}

3.修改HelloController类

package com.myimooc.boot.start.controller;

import com.myimooc.boot.start.domain.JsonResult;
import com.myimooc.boot.start.domain.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * <br>
 * 标题: 基于REST的Controller<br>
 * 描述: 返直接返回方法的响应内容<br>
 *
 * @author zc
 * @date 2018/04/19
 */
@RestController
public class HelloController {

    @Autowired
    private Resource resource;

    @GetMapping("/hello")
    public Object hello(){
        return "Hello SpringBoot!";
    }

    @GetMapping("/getResource")
    public JsonResult getResource(){
        Resource target = new Resource();
        BeanUtils.copyProperties(resource,target);
        return JsonResult.ok(target);
    }
}

第三章:技术整合

3-1 模版引擎

Spring Boot 整合模版引擎

  • Spring Boot 整合 Freemarker
  • Spring Boot 整合 Thymeleaf

代码编写

1.修改pom引入依赖

        <!--引入 Freemarker 模版引擎依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <!--引入 Thymeleaf 模版引擎依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

2.修改application.properties


#------------ Server 服务端相关配置
# 配置 api 端口号
#server.port=8080
# 配置 context-path,一般在正式发布时不配置
#server.servlet.context-path=/start
# 错误页,指定发生错误时,跳转的URL -> BasicErrorController
#server.error.path=/error
# session 最大超时时间(单位:秒;默认值:30分钟)
server.servlet.session.timeout=3600
# 绑定ID地址,如果本机不是该ID地址则抛出异常,根据具体业务需求来设置
#server.address=192.168.1.8

# tomcat 最大线程数(默认值:200)
#server.tomcat.max-threads=250
# tomcat 的URI编码
server.tomcat.uri-encoding=UTF-8

# 配置 i18N 资源文件,供 thymeleaf 读取
spring.messages.basename=i18n/messages
spring.messages.cache-duration=3600
spring.messages.encoding=UTF-8

# 设置静态文件路径,js、css等
spring.mvc.static-path-pattern=/static/**

#------------ Freemarker 静态资源配置
# 设置 ftl 文件路径
spring.freemarker.template-loader-path=classpath:/templates/
# 关闭缓存,即时刷新,生产环境需改为true
spring.freemarker.cache=false
spring.freemarker.charset=UTF-8
spring.freemarker.check-template-location=true
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=true
spring.freemarker.expose-session-attributes=true
spring.freemarker.request-context-attribute=request
spring.freemarker.suffix=.ftl

#------------ Thymeleaf 静态资源配置
spring.thymeleaf.prefix=classpath:/templates/
# 关闭缓存,即时刷新,生产环境需改为true
spring.thymeleaf.cache=false
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.servlet.content-type=text/html

3.编写FreemarkerController类

package com.myimooc.boot.start.controller;

import com.myimooc.boot.start.domain.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * <br>
 * 标题: Freemarker<br>
 * 描述: 整合 Freemarker<br>
 *
 * @author zc
 * @date 2018/04/25
 */
@Controller
@RequestMapping("ftl")
public class FreemarkerController {

    @Autowired
    private Resource resource;

    @GetMapping("/index")
    public String index(ModelMap map){
        map.addAttribute("resource",resource);
        return "freemarker/index";
    }

    @GetMapping("/center")
    public String center(){
        return "freemarker/center/center";
    }
}

4.编写ThymeleafController类

package com.myimooc.boot.start.controller;

import com.myimooc.boot.start.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <br>
 * 标题: Thymeleaf<br>
 * 描述: 整合 Thymeleaf<br>
 *
 * @author zc
 * @date 2018/04/25
 */
@Controller
@RequestMapping("th")
public class ThymeleafController {

    @RequestMapping("/index")
    public String index(ModelMap map) {
        map.addAttribute("name", "thymeleaf-imooc");
        return "thymeleaf/index";
    }

    @RequestMapping("center")
    public String center() {
        return "thymeleaf/center/center";
    }

    @RequestMapping("test")
    public String test(ModelMap map) {

        User u = new User();
        u.setName("superadmin");
        u.setAge(10);
        u.setPassword("123465");
        u.setBirthday(new Date());
        u.setNote("<font color='green'><b>hello imooc</b></font>");

        map.addAttribute("user", u);

        User u1 = new User();
        u1.setAge(19);
        u1.setName("imooc");
        u1.setPassword("123456");
        u1.setBirthday(new Date());

        User u2 = new User();
        u2.setAge(17);
        u2.setName("LeeCX");
        u2.setPassword("123456");
        u2.setBirthday(new Date());

        List<User> userList = new ArrayList<>();
        userList.add(u);
        userList.add(u1);
        userList.add(u2);

        map.addAttribute("userList", userList);

        return "thymeleaf/test";
    }

    @PostMapping("postform")
    public String postform(User user) {

        System.out.println("姓名:" + user.getName());
        System.out.println("年龄:" + user.getAge());

        return "redirect:/th/test";
    }

    @RequestMapping("showerror")
    public String showerror(User user) {

        int a = 1 / 0;

        return "redirect:/th/test";
    }
}

5.受篇幅限制,页面代码就不显示了,源码请到github查看。完成后的目录结构如下

clipboard.png

3-2 全局异常

代码编写

1.编写ErrorController类

package com.myimooc.boot.start.controller;

import com.myimooc.boot.start.domain.JsonResult;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * <br>
 * 标题: 错误页演示<br>
 * 描述: 跳转至错误页<br>
 *
 * @author zc
 * @date 2018/04/25
 */
@Controller
@RequestMapping("err")
public class ErrorController {

    @RequestMapping("/error")
    public String error() {
        int a = 1 / 0;
        return "thymeleaf/error";
    }
    
    @RequestMapping("/ajaxerror")
    public String ajaxerror() {
        return "thymeleaf/ajaxerror";
    }
    
    @RequestMapping("/getAjaxerror")
    @ResponseBody
    public JsonResult getAjaxerror() {
        int a = 1 / 0;
        return JsonResult.ok();
    }
}

2.编写GlobalExceptionHandler类

package com.myimooc.boot.start.exception;

import com.myimooc.boot.start.domain.JsonResult;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;

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

/**
 * <br>
 * 标题: 全局异常捕获,兼容 web 和 ajax<br>
 * 描述: 使用 @ControllerAdvice 声明当前是助手类<br>
 *
 * @author zc
 * @date 2018/04/25
 */
@ControllerAdvice
@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final String ERROR_VIEW = "error";

    @ExceptionHandler(Exception.class)
    public Object handler(HttpServletRequest request, HttpServletResponse response, Exception e) {
        e.printStackTrace();

        if (isAjax(request)) {
            return this.responseByAjax(request, response, e);
        }
        return this.responseByWeb(request, response, e);
    }

    private boolean isAjax(HttpServletRequest request) {
        return (request.getHeader("X-Requested-With") != null) && ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) ;
    }

    private JsonResult responseByAjax(HttpServletRequest request, HttpServletResponse response, Exception e) {
        return JsonResult.errException(e.getMessage());
    }

    private ModelAndView responseByWeb(HttpServletRequest request, HttpServletResponse response, Exception e) {
        ModelAndView mav = new ModelAndView();
        mav.setViewName(ERROR_VIEW);
        mav.addObject("exception", e);
        mav.addObject("url", request.getRequestURL());
        return mav;
    }
}

3-3 持久框架

Spring Boot 整合 MyBatis

  • 使用generatorConfig生成mapper以及pojo
  • 实现基于MyBatis的CRUD功能
  • 整合MyBatis-pagehelper实现分页
  • 自定义mapper的实现

受篇幅限制,代码就不显示了,源码请到github查看。

3-4 缓存技术

Spring Boot 整合 Redis

代码编写

1.引入redis依赖

<!--引入redis依赖-->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.配置application.properties

#------------ redis 配置
# redis 数据库索引(默认值:0)
spring.redis.database=0
# redis 服务器地址
spring.redis.host=127.0.0.1
# redis 服务器端口
spring.redis.port=6379

3.编写JsonUtils类

package com.myimooc.boot.start.util;

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

import java.util.List;

/**
 * <br>
 * 标题: 定义响应结构, 转换类<br>
 * 描述: Json工具<br>
 *
 * @author zc
 * @date 2018/04/26
 */
public class JsonUtils {

    // 定义jackson对象
    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * 将对象转换成json字符串。
     * <p>Title: pojoToJson</p>
     * <p>Description: </p>
     * @param data
     * @return
     */
    public static String objectToJson(Object data) {
        try {
            String string = MAPPER.writeValueAsString(data);
            return string;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 将json结果集转化为对象
     * 
     * @param jsonData json数据
     * @param beanType 对象中的object类型
     * @return
     */
    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
        try {
            T t = MAPPER.readValue(jsonData, beanType);
            return t;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 将json数据转换成pojo对象list
     * @param jsonData
     * @param beanType
     * @return
     */
    public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) {
        JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
        try {
            List<T> list = MAPPER.readValue(jsonData, javaType);
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return null;
    }
    
}

4.编写RedisOperator类

package com.myimooc.boot.start.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * <br>
 * 标题: Redis 常用方法封装<br>
 * 描述: 使用redisTemplate的操作实现类<br>
 *
 * @author zc
 * @date 2018/04/26
 */
@Component
public class RedisOperator {

    @Autowired
    private StringRedisTemplate redisTemplate;

    // Key(键),简单的key-value操作

    /**
     * 实现命令:TTL key,以秒为单位,返回给定 key的剩余生存时间(TTL, time to live)。
     *
     * @param key
     * @return
     */
    public long ttl(String key) {
        return redisTemplate.getExpire(key);
    }

    /**
     * 实现命令:expire 设置过期时间,单位秒
     *
     * @param key
     * @return
     */
    public void expire(String key, long timeout) {
        redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 实现命令:INCR key,增加key一次
     *
     * @param key
     * @return
     */
    public long incr(String key, long delta) {
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 实现命令:KEYS pattern,查找所有符合给定模式 pattern的 key
     */
    public Set<String> keys(String pattern) {
        return redisTemplate.keys(pattern);
    }

    /**
     * 实现命令:DEL key,删除一个key
     *
     * @param key
     */
    public void del(String key) {
        redisTemplate.delete(key);
    }

    // String(字符串)

    /**
     * 实现命令:SET key value,设置一个key-value(将字符串值 value关联到 key)
     *
     * @param key
     * @param value
     */
    public void set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 实现命令:SET key value EX seconds,设置key-value和超时时间(秒)
     *
     * @param key
     * @param value
     * @param timeout (以秒为单位)
     */
    public void set(String key, String value, long timeout) {
        redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 实现命令:GET key,返回 key所关联的字符串值。
     *
     * @param key
     * @return value
     */
    public String get(String key) {
        return (String) redisTemplate.opsForValue().get(key);
    }

    // Hash(哈希表)

    /**
     * 实现命令:HSET key field value,将哈希表 key中的域 field的值设为 value
     *
     * @param key
     * @param field
     * @param value
     */
    public void hset(String key, String field, Object value) {
        redisTemplate.opsForHash().put(key, field, value);
    }

    /**
     * 实现命令:HGET key field,返回哈希表 key中给定域 field的值
     *
     * @param key
     * @param field
     * @return
     */
    public String hget(String key, String field) {
        return (String) redisTemplate.opsForHash().get(key, field);
    }

    /**
     * 实现命令:HDEL key field [field ...],删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。
     *
     * @param key
     * @param fields
     */
    public void hdel(String key, Object... fields) {
        redisTemplate.opsForHash().delete(key, fields);
    }

    /**
     * 实现命令:HGETALL key,返回哈希表 key中,所有的域和值。
     *
     * @param key
     * @return
     */
    public Map<Object, Object> hgetall(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    // List(列表)

    /**
     * 实现命令:LPUSH key value,将一个值 value插入到列表 key的表头
     *
     * @param key
     * @param value
     * @return 执行 LPUSH命令后,列表的长度。
     */
    public long lpush(String key, String value) {
        return redisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * 实现命令:LPOP key,移除并返回列表 key的头元素。
     *
     * @param key
     * @return 列表key的头元素。
     */
    public String lpop(String key) {
        return (String) redisTemplate.opsForList().leftPop(key);
    }

    /**
     * 实现命令:RPUSH key value,将一个值 value插入到列表 key的表尾(最右边)。
     *
     * @param key
     * @param value
     * @return 执行 LPUSH命令后,列表的长度。
     */
    public long rpush(String key, String value) {
        return redisTemplate.opsForList().rightPush(key, value);
    }

}

5.编写RedisController类

package com.myimooc.boot.start.controller;

import com.myimooc.boot.start.dao.po.SysUser;
import com.myimooc.boot.start.domain.JsonResult;
import com.myimooc.boot.start.domain.User;
import com.myimooc.boot.start.util.JsonUtils;
import com.myimooc.boot.start.util.RedisOperator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <br>
 * 标题: 整合redis<br>
 * 描述: redis访问<br>
 *
 * @author zc
 * @date 2018/04/26
 */
@RestController
@RequestMapping("redis")
public class RedisController {

    @Autowired
    private StringRedisTemplate strRedis;

    @Autowired
    private RedisOperator redis;

    @RequestMapping("/test")
    public JsonResult test() {
        strRedis.opsForValue().set("imooc-cache", "hello 慕课网~~~~~~");
        SysUser user = new SysUser();
        user.setId("100111");
        user.setUsername("imooc");
        user.setPassword("abc123");
        user.setIsDelete(0);
        user.setRegistTime(new Date());
        strRedis.opsForValue().set("json:user", JsonUtils.objectToJson(user));
        SysUser jsonUser = JsonUtils.jsonToPojo(strRedis.opsForValue().get("json:user"), SysUser.class);
        return JsonResult.ok(jsonUser);
    }

    @RequestMapping("/getJsonList")
    public JsonResult getJsonList() {

        User user = new User();
        user.setAge(18);
        user.setName("慕课网");
        user.setPassword("123456");
        user.setBirthday(new Date());

        User u1 = new User();
        u1.setAge(19);
        u1.setName("imooc");
        u1.setPassword("123456");
        u1.setBirthday(new Date());

        User u2 = new User();
        u2.setAge(17);
        u2.setName("hello imooc");
        u2.setPassword("123456");
        u2.setBirthday(new Date());

        List<User> userList = new ArrayList<>();
        userList.add(user);
        userList.add(u1);
        userList.add(u2);

        redis.set("json:info:userlist", JsonUtils.objectToJson(userList), 2000);

        String userListJson = redis.get("json:info:userlist");
        List<User> userListBorn = JsonUtils.jsonToList(userListJson, User.class);

        return JsonResult.ok(userListBorn);
    }
}

3-5 定时任务

代码编写

1.修改BootStartApplication启动类,增加注解

@EnableScheduling

2.编写TestTask类

package com.myimooc.boot.start.tasks;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * <br>
 * 标题: 测试定时任务<br>
 * 描述: 自定义定时任务<br>
 *
 * @author zc
 * @date 2018/04/26
 */
@Component
public class TestTask {

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

    /**
     * 定义每过3秒执行任务
     * 支持使用 @Scheduled(cron = "4-40 * * * * ?") cron表达式
     */
    @Scheduled(fixedRate = 3000)
    public void reportCurrentTime() {
        System.out.println("现在时间:" + dateFormat.format(new Date()));
    }
}

3-6 异步任务

异步任务使用场景

  • 发送短信
  • 发送邮件
  • APP消息推送
  • 提高效率

代码编写

1.修改BootStartApplication启动类,增加注解

@EnableAsync

2.编写AsyncTask类

package com.myimooc.boot.start.tasks;

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;

import java.util.concurrent.Future;

/**
 * <br>
 * 标题: 自定义异步执行任务<br>
 * 描述: 异步方法需使用 @Async 注解<br>
 * 判断任务是否完成,必须返回 Future 接口
 * @author zc
 * @date 2018/04/26
 */
@Component
public class AsyncTask {

    @Async
    public Future<Boolean> doTask11() throws Exception {
        long start = System.currentTimeMillis();
        Thread.sleep(1000);
        long end = System.currentTimeMillis();
        System.out.println("任务1耗时:" + (end - start) + "毫秒");
        return new AsyncResult<>(true);
    }

    @Async
    public Future<Boolean> doTask22() throws Exception {
        long start = System.currentTimeMillis();
        Thread.sleep(700);
        long end = System.currentTimeMillis();
        System.out.println("任务2耗时:" + (end - start) + "毫秒");
        return new AsyncResult<>(true);
    }

    @Async
    public Future<Boolean> doTask33() throws Exception {
        long start = System.currentTimeMillis();
        Thread.sleep(600);
        long end = System.currentTimeMillis();
        System.out.println("任务3耗时:" + (end - start) + "毫秒");
        return new AsyncResult<>(true);
    }
}

3.编写DoTaskController类

package com.myimooc.boot.start.tasks;

import com.myimooc.boot.start.domain.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.Future;

/**
 * <br>
 * 标题: 调用异步方法的controller<br>
 * 描述: 异步任务<br>
 *
 * @author zc
 * @date 2018/04/26
 */
@RestController
@RequestMapping("/tasks")
public class DoTaskController {

    @Autowired
    private AsyncTask asyncTask;

    @RequestMapping("/asyncTask")
    public JsonResult asyncTask() throws Exception {
        long start = System.currentTimeMillis();
        Future<Boolean> a = asyncTask.doTask11();
        Future<Boolean> b = asyncTask.doTask22();
        Future<Boolean> c = asyncTask.doTask33();
        while (!a.isDone() || !b.isDone() || !c.isDone()) {
            if (a.isDone() && b.isDone() && c.isDone()) {
                break;
            }
        }
        long end = System.currentTimeMillis();
        String times = "任务全部完成,总耗时:" + (end - start) + "毫秒";
        System.out.println(times);
        return JsonResult.ok(times);
    }
}

3-7 用拦截器

Spring Boot 拦截器的使用

  • 使用注解@Configuration配置拦截器
  • 继承WebMvcConfigurerAdapter
  • 重新addInterceptors增加需要的拦截器地址

代码编写

1.编写OneInterceptor类

package com.myimooc.boot.start.interceptor;

import com.myimooc.boot.start.domain.JsonResult;
import com.myimooc.boot.start.util.JsonUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;

/**
 * <br>
 * 标题: 自定义拦截器一<br>
 * 描述: 拦截器<br>
 *
 * @author zc
 * @date 2018/04/26
 */
public class OneInterceptor implements HandlerInterceptor {

    /**
     * 在请求处理之前进行调用(Controller方法调用之前)
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object object) throws Exception {

        System.out.println("被one拦截,放行...");
        return true;

//         当校验不通过时,返回 ajax 错误信息
//        if (true) {
//            this.returnErrorResponse(response, JsonResult.errMsg("被one拦截"));
//        }
//        return false;
    }

    /**
     * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object object, ModelAndView mv)
            throws Exception {
        // 可以修改返回的数据
    }

    /**
     * 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行
     * (主要是用于进行资源清理工作)
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object object, Exception ex)
            throws Exception {

    }

    private void returnErrorResponse(HttpServletResponse response, JsonResult result) throws Exception {
        OutputStream out = null;
        try {
            response.setCharacterEncoding("utf-8");
            response.setContentType("text/json");
            out = response.getOutputStream();
            out.write(JsonUtils.objectToJson(result).getBytes("utf-8"));
            out.flush();
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }
}

2.编写TwoInterceptor类

package com.myimooc.boot.start.interceptor;

import com.myimooc.boot.start.domain.JsonResult;
import com.myimooc.boot.start.util.JsonUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;

/**
 * <br>
 * 标题: 自定义拦截器二<br>
 * 描述: 拦截器<br>
 *
 * @author zc
 * @date 2018/04/26
 */
public class TwoInterceptor implements HandlerInterceptor  {

    /**
     * 在请求处理之前进行调用(Controller方法调用之前)
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
        if (true) {
            returnErrorResponse(response, JsonResult.errMsg("被two拦截"));
        }
        System.out.println("被two拦截...");
        return false;
    }
    
    /**
     * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView mv)
            throws Exception {
    }
    
    /**
     * 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception ex)
            throws Exception {
    }
    
    public void returnErrorResponse(HttpServletResponse response, JsonResult result) throws Exception{
        OutputStream out=null;
        try{
            response.setCharacterEncoding("utf-8");
            response.setContentType("text/json");
            out = response.getOutputStream();
            out.write(JsonUtils.objectToJson(result).getBytes("utf-8"));
            out.flush();
        } finally{
            if(out!=null){
                out.close();
            }
        }
    }
}

3.编写WebMvcConfig类

package com.myimooc.boot.start.config;

import com.myimooc.boot.start.interceptor.OneInterceptor;
import com.myimooc.boot.start.interceptor.TwoInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/**
 * <br>
 * 标题: 自定义配置类<br>
 * 描述: 注册自定义的拦截器<br>
 *
 * @author zc
 * @date 2018/04/26
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        /**
         * 拦截器按照顺序执行
         */
        registry.addInterceptor(new TwoInterceptor()).addPathPatterns("/two/**").addPathPatterns("/one/**");
        registry.addInterceptor(new OneInterceptor()).addPathPatterns("/one/**");
        super.addInterceptors(registry);
    }
}

第四章:课程总结

4-1 课程总结

课程总结

  • 搭建项目
  • 模版引擎
  • 全局异常
  • 持久框架
  • 缓存技术
  • 定时任务
  • 异步任务
  • 使用拦截器

妙手空空
1.3k 声望370 粉丝

博观而约取,厚积而薄发