SpringBoot学习笔记

博主 3177 2020-07-20

SpringBoot学习过程的案例记录
我参考的SpringBoot教程

第一章 SpringBoot框架入门

1.1 SpringBoot简介

image.png

1.2 SpringBoot的特性

image.png

1.3 SpringBoot 4大核心

image.png

第二章 SpringBoot入门案例

2.1 学会如何创建一个SpringBoot web工程

new一个module,选择Spring Initializr
image.png
设置项目名称,版本等
image.png
选择Web -> Spring Web
image.png
设置模块名字
image.png

2.2 运行一个web工程

package com.learn.springboot.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class IndexController {

    @RequestMapping(value = "/springboot/say")
    @ResponseBody
    public String say(ModelAndView modelAndView){
        System.out.println(modelAndView);
        return "Hello spring Boot";
    }
}

然后直接运行Application的main方法即可

2.3 application.properties配置

#设置内嵌Tomcat端口号
server.port=8099

#设置上下文根
server.servlet.context-path=/springboot

2.4 使用application.yml 或者application.yaml

server:
  port: 10000
  servlet:
    context-path: /yaml

2.5 两种配置文件同时存在的情况

以.properties为准,忽略另一个配置文件

2.6 多环境下的核心配置文件的使用

2.6.1 properties文件
工作中开发的环境:开发环境/测试环境/准生产环境/生产环境等
配置文件以application-开头
eg:
application-dev.properties
application-test.properties

在主配置文件激活配置文件

#主核心配置文件
#激活使用的配置文件
spring.profiles.active=dev

2.6.2 yaml文件
同样配置文件以application-开头
eg:
application-product.yml

在主配置文件激活配置文件

spring:
  profiles:
    active: test

2.7 自定义配置

SpringBoot在核心配置文件application.properties自定义配置
在application.properties中写上

server.port=8080
server.servlet.context-path=/

school.name=wuminggao
websit=https://www.wuminggao.com

使用注解@Value注入属性

@Controller
public class IndexController {

    @Value("${school.name}")
    private String schoolName;

    @RequestMapping("/say")
    @ResponseBody
    public String say(){
        return "Hello SpringBoot multi-environment";
    }
}

2.8 将自定义配置映射到对象

SpringBoot在核心配置文件将自定义配置映射成一个对象
使用@ConfigurationProperties(prefix = "xx")填写前缀

application.properties

server.port=8080
server.servlet.context-path=/

school.name=wuminggao
school.website=https://www.wuminggao.com

创建一个配置类

@Component //将此类交给spring容器进行管理
@ConfigurationProperties(prefix = "school")
public class School {
    private String name;
    private String website;

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

将其注入School类的实例

@Controller
public class IndexController {

    @Autowired
    private School school;

    @RequestMapping("/say")
    @ResponseBody
    public String say(){
        System.out.println("schoolName:" + school.getName() + ",website");
        return "Hello SpringBoot  " + ",school.name:" + school.getName() +
                ",school.website:" + school.getWebsite();
    }
}

2.9 SpringBoot集成jsp

首先在pom.xml添加jsp依赖

<!--		引入SpringBoot内嵌Tomcat对jsp的解析包
			不添加解析不了jsp
			仅仅只是展示jsp页面,只添加以下一个依赖
-->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
		</dependency>

在pom.xml指定jsp编译路径

<build>

<!--		SpringBoot项目默认推荐使用的前端引擎是thymeleaf
			我们要使用SpringBoot集成jsp,手动指定jsp最后编译的路径
			而且SpringBoot集成jsp编译jsp的路径是SpringBoot规定好的位置
			META-INF/resources

-->
		<resources>
			<resource>
<!--				源文件夹-->
				<directory>src/main/webapp</directory>
<!--				指定编译到目标文件夹-->
				<targetPath>META-INF/resources</targetPath>
<!--				指定源文件夹中的哪个文件需要进行编译-->
				<includes>
					<include>*.*</include>
				</includes>
			</resource>
		</resources>
</build>

在application.properties配置视图解析器


#配置视图解析器
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp

在src/main/下创建webapp目录,并设置为Web Resource的路径
在webapp下创建say.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>say</title>
</head>
<body>
say:${msg}
</body>
</html>

在Controller中转发请求到jsp

@Controller
public class IndexController {

    @RequestMapping("/say")
    public ModelAndView say(ModelAndView modelAndView){
        modelAndView.addObject("msg", "Hello, SpringBoot");
        modelAndView.setViewName("say");
        return modelAndView;
    }
}

第三章 SpringBoot框架Web开发

3.1 集成MyBatis

1)添加mybatis依赖,mysql驱动

<!--		MySql驱动-->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

<!--		MyBatis整合SpringBoot框架的起步依赖-->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.0.0</version>
		</dependency>

2)MyBatis逆向工程生成实体bean,映射文件,DAO接口
在module根目录下,创建一个xml文件:GeneratorMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!-- 指定连接数据库的 JDBC 驱动包所在位置,指定到你本机的完整路径 -->
    <classPathEntry location="E:\mysql-connector-java-5.1.38.jar"/>

    <!-- 配置 table 表信息内容体,targetRuntime 指定采用 MyBatis3 的版本 -->
    <context id="tables" targetRuntime="MyBatis3">
        <!-- 抑制生成注释,由于生成的注释都是英文的,可以不让它生成 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        <!-- 配置数据库连接信息 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/springboot"
                        userId="root"
                        password="123456">
        </jdbcConnection>
        <!-- 生成 model 类,targetPackage
        指定 model 类的包名, targetProject
        指定 生成的 model 放在 eclipse 的哪个工程下面-->
        <javaModelGenerator targetPackage="com.abc.springboot.model" targetProject="src/main/java">
            <property name="enableSubPackages" value="false" />
            <property name="trimStrings" value="false" />
        </javaModelGenerator>
        <!-- 生成 MyBatis 的 Mapper.xml 文件,targetPackage
        指定 mapper.xml 文件的 包名, targetProject
        指定生成的 mapper.xml 放在 eclipse 的哪个工程下面 -->
        <sqlMapGenerator targetPackage="com.abc.springboot.mapper"
                         targetProject="src/main/java">
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        <!-- 生成 MyBatis 的 Mapper 接口类文件,targetPackage 指定 Mapper 接口类的包 名, targetProject 指定生成的 Mapper 接口放在 eclipse 的哪个工程下面 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.abc.springboot.mapper" targetProject="src/main/java">
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>
        <!-- 数据库表名及对应的 Java 模型类名 -->
        <table tableName="t_student" domainObjectName="Student"
               enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false"
               enableSelectByExample="false" selectByExampleQueryId="false"/>
    </context>
</generatorConfiguration>

在pom.xml文件中添加mysql逆向工程依赖的插件

<!--mybatis 代码自动生成插件-->
<plugin>
	<groupId>org.mybatis.generator</groupId>
	<artifactId>mybatis-generator-maven-plugin</artifactId>
	<version>1.3.6</version>
	<configuration>
	<!--配置文件的位置-->
		<configurationFile>GeneratorMapper.xml</configurationFile>
		<verbose>true</verbose>
		<overwrite>true</overwrite>
	</configuration>
</plugin>

然后使用generator工具
image.png
直接生成StudentMapper接口和xml配置文件,以及Student实体类
image.png

DAO接口

public interface StudentMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(Student record);

    int insertSelective(Student record);

    Student selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(Student record);

    int updateByPrimaryKey(Student record);
}

对应的MyBatis mapper配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.learn.springboot.mapper.StudentMapper">

  <resultMap id="BaseResultMap" type="com.learn.springboot.model.Student">
<!--
      id标签:只能修饰主键字段
      column标签:数据库中的字段名称
      property:映射对象的属性名称
      result:主键以外的字段
-->
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="age" jdbcType="INTEGER" property="age" />
  </resultMap>

<!--    sql语句片段,将公共的部分抽取出来-->
  <sql id="Base_Column_List">
    id, name, age
  </sql>

  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from t_student
    where id = #{id,jdbcType=INTEGER}
  </select>

  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    delete from t_student
    where id = #{id,jdbcType=INTEGER}
  </delete>

  <insert id="insert" parameterType="com.learn.springboot.model.Student">
    insert into t_student (id, name, age
      )
    values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER}
      )
  </insert>

  <insert id="insertSelective" parameterType="com.learn.springboot.model.Student">
    insert into t_student
--     拼串,要插入的字段
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="name != null">
        name,
      </if>
      <if test="age != null">
        age,
      </if>
    </trim>

    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=INTEGER},
      </if>
      <if test="name != null">
        #{name,jdbcType=VARCHAR},
      </if>
      <if test="age != null">
        #{age,jdbcType=INTEGER},
      </if>
    </trim>
  </insert>


  <update id="updateByPrimaryKeySelective" parameterType="com.learn.springboot.model.Student">
    update t_student
    <set>
      <if test="name != null">
        name = #{name,jdbcType=VARCHAR},
      </if>
      <if test="age != null">
        age = #{age,jdbcType=INTEGER},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>


  <update id="updateByPrimaryKey" parameterType="com.learn.springboot.model.Student">
    update t_student
    set name = #{name,jdbcType=VARCHAR},
      age = #{age,jdbcType=INTEGER}
    where id = #{id,jdbcType=INTEGER}
  </update>


</mapper>

实体bean

public class Student {
    private Integer id;

    private String name;

    private Integer age;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

注意:
对数据库中的表字段进行命名的时候,如果字段是多个单词组成,使用下划线隔开。如user_name,user_age
逆向工程自动生成实体bean时,使用下划线作为单词分割符,然后使用驼峰命名法生成bean的属性: 数据库字段user_name -> 类的属性userName
如果数据库字段不用下划线分隔,逆向工程将其视为一个单词: 数据库字段userName -> 类的属性username

3)编写Service层接口和实现类
在Application入口添加注解扫描Mapper包
使用@MapperScan(basePackages = "com.learn.springboot.mapper")//开启扫描mapper接口的包和子包

也可以在需要的Mapper类上添加@Mapper注解,表示扫描这个类

在pom.xml配置资源文件夹,扫描mapper包中的配置文件

<resources>
			<resource>
				<directory>src/main/java</directory>
				<includes>
					<include>**/*.xml</include>
					<include>**/*.properties</include>
				</includes>
			</resource>
		</resources>

扫描Mapper配置文件的另一种方式:
在resources下添加mapper目录,把Mapper配置文件放到该目录下
在主配置文件添加

mybatis.mapper-locations=classpath:mapper/**.xml

4)在主配置文件配置连接数据库的信息等
注意Mysql8.0以上驱动名字为com.mysql.cj.jdbc.Driver

server.port=8080
server.servlet.context-path=/

spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=xxxxxx
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

3.2 SpringBoot事务

在SpringBoot项目下使用事务
在service实现类或者方法上使用@Transactional注解,开启事务


3.3 SpringMVC其他常用注解

3.3.1 @RestController注解
一种Controller的注解,表示@Controlle+方法上加@ResponseBody
表示该控制器所有方法都返回json对象

3.3.2 @GetMapping
只支持get请求
相当于@RequestMapping(value = "/xxx", method = RequestMethod.GET)
如果使用Post请求会报405错误
一般用于查询操作

3.3.3 @PostMapping
只支持post请求
相当于@RequestMapping(value = "/xxx", method = RequestMethod.POST)
一般用于新增操作

3.3.4 @PutMapping
只支持put请求
一般用于修改操作,更新操作

3.3.5 @DeleteMapping
只支持delete请求
一般用于删除操作

3.4 RESTful

3.4.1 认识RESTful
image.png

3.4.2 使用RESTful风格接收请求参数

@RequestMapping("/student/detail/{id}/{age}")
    public Student student2(@PathVariable("id") Integer id, @PathVariable("age") Integer age){
        Student student = new Student();
        student.setId(id);
        student.setAge(age);
        return student;

    }

使用{参数名}和@PathVariable("参数名")来接收和获取参数

出现错误:

@RequestMapping("/student/detail/{id}/{age}")
    public Student student2(@PathVariable("id") Integer id, @PathVariable("age") Integer age){
        Student student = new Student();
        student.setId(id);
        student.setAge(age);
        return student;

    }

    @RequestMapping("/student/detail/{id}/{state}")
    public Object student3(@PathVariable("id") Integer id, @PathVariable("state") Integer state){
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("id", id) ;
        hashMap.put("state", state);
        return hashMap;

    }

这个代码会出现请求路径无法判断的IllegalStateException错误,错误码status=500
我们可以用不同的请求方式区分:Get请求,Post请求,delte请求,put请求等
eg:

@GetMapping("/student/detail/{id}/{age}")
    public Student student2(@PathVariable("id") Integer id, @PathVariable("age") Integer age){
        Student student = new Student();
        student.setId(id);
        student.setAge(age);
        return student;

    }

    @DeleteMapping("/student/detail/{id}/{state}")
    public Object student3(@PathVariable("id") Integer id, @PathVariable("state") Integer state){
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("id", id) ;
        hashMap.put("state", state);
        return hashMap;
    }

注意
RESTful请求参数尽量不要使用动词,使用名词
分页,排序等操作,不需要使用斜杠传参数

3.5 SpringBoot集成Redis

添加依赖:添加操作redis数据类型的依赖

<!--		Springboot集成Redis依赖-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>

配置连接redis的信息

spring.redis.host=xxx
spring.redis.port=6379
spring.redis.password=1234

业务层:

@Service
public class StudentServiceImpl implements StudentService {
    //Spring-data-redis提供的操作redis的模板对象
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Override
    public void put(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    @Override
    public String get(String key) {
        String o = (String)redisTemplate.opsForValue().get(key);
        return o;
    }
}

控制层:

@RestController
public class StudentController {

    @Autowired
    private StudentService studentService;

    @PutMapping("/put")
    public Object put(String key, String value){

        studentService.put(key, value);

        return "值已经放入redis";
    }

    @GetMapping("/get")
    public Object get(String key){

        String s = studentService.get(key);

        return s;
    }
}

3.6 SpringBoot集成Dubbo

接口工程:提供业务接口和实体bean
服务提供者:业务接口的实现类,调用数据持久层,将服务暴露到注册中心
-添加依赖(dubbo,注册中心,接口工程)
-配置服务提供者核心配置文件
服务消费者:处理浏览器客户端发送的请求,从注册中心调用服务提供者所提供的服务
-添加依赖(dubbo,注册中心,接口工程)
-配置服务消费者核心配置文件

参考我的SpringBoot案例
里面的020 021 022

使用到的新注解
1)@EnableDubboConfiguration//开启dubbo配置
在SpringBoot入口处使用
2)@Service(interfaceClass = StudentService.class, version = "1.0.0", timeout = 15000)
注意是com.alibaba.dubbo.config.annotation.Service;
用于提供者暴露接口,添加在实现类上面
3)@Reference(interfaceClass = StudentService.class, version = "1.0.0", check = true)
注意是com.alibaba.dubbo.config.annotation.Reference;
控制层用于注入实现类,添加在属性上面

配置消费者

#设置内嵌TOmcat端口号
server.port=8082

server.servlet.context-path=/

#设置dubbo的配置
spring.application.name=022-springboot-dubbo-consumer

#设置注册中心
spring.dubbo.registry=zookeeper://localhost:2181

配置提供者

#设置内嵌TOmcat端口号
server.port=8081

server.servlet.context-path=/

#设置dubbo的配置
spring.application.name=021-springboot-dubbo-provider
#当前工程是一个服务提供者
spring.dubbo.server=true

#设置注册中心
spring.dubbo.registry=zookeeper://localhost:2181


3.7 SpirngBoot集成Dubbo和SSM

接口工程:存放实体Bean和业务接口
服务提供者:它是一个SpringBoot Web项目,集成MyBatis,Redis
-依赖:MyBatis,Redis,Dubbo,zookeeper,MySQL,接口工程
-配置:SpringBoot核心配置文件
----配置连接数据库
----配置连接Redis
----配置Dubbo
----配置Tomcat
服务消费者:它是一个SpringBoot Web项目,集成Jsp,Dubbo
-依赖:Dubbo,zookeeper,Jsp,接口工程
-配置:SpringBoot核心配置文件
----视图解析器
----配置Dubbo
----配置Tomcat

第四章 SpringBoot非Web应用程序

4.1 创建一个SpringBoot非web工程

在创建时,单击Web后,不点击Spring Web选项
image.png
直接单击next

4.2 获取SpringBoot容器中的bean对象

方式一:

@SpringBootApplication
public class Application {

	public static void main(String[] args) {
		/**
		 * SpringBoot程序启动后,返回值是ConfigurableApplicationContext,它也是一个Spring容器
		 * 相当于原来Spring容器中启动ClasspathXmlApplicationContext;
		 */

		ConfigurableApplicationContext run = SpringApplication.run(Application.class, args);
		StudentService studentServiceImpl = run.getBean("studentServiceImpl", StudentService.class);
		String s = studentServiceImpl.sayHello();
		System.out.println(s);


	}

}

方式二:

@SpringBootApplication
public class Application implements CommandLineRunner {

	@Autowired
	private StudentService studentService;

	public static void main(String[] args) {

		SpringApplication.run(Application.class, args);
	}

	//重写CommandLineRunner的run方法
	@Override
	public void run(String... args) throws Exception {
		String s = studentService.sayHello(" World");
		System.out.println(s);
	}
}

4.3 关闭SpringBoot启动图标

@SpringBootApplication
public class Application {

	public static void main(String[] args) {

//		SpringApplication.run(Application.class, args);
		SpringApplication springApplication = new SpringApplication(Application.class);
		//关闭启动logo
		springApplication.setBannerMode(Banner.Mode.OFF);
		springApplication.run(args);

	}

}

利用网站生成logo, 网站:https://www.bootschool.net/ascii 或 者 http://patorjk.com/software/taag/
在resource下新建banner.txt
将生成内容copy进去即可

第五章 SpringBoot使用拦截器

步骤
1)定义一个拦截器,实现HandlerInterceptor接口

public class UserInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        System.out.println("进入拦截器");
        //编写业务拦截的规则
        //从session获取用户的信息
        User user = (User)request.getSession().getAttribute("user");

        if (null == user){
            response.sendRedirect(request.getContextPath() + "/user/error");
            return false;
        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

2)创建一个配置类(即:在SpringMVC配置文件中使用mvc:interceptor标签)

@Configuration//定义此类为配置类
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(
                new UserInterceptor())
                .addPathPatterns("/user/**")//拦截user下的所有访问请求
                .excludePathPatterns(Arrays.asList("/user/out", "/user/error", "/user/login"));//排除掉的路径,不登录也可以访问


    }
}

3)编写控制层方法

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

    /**
     * 用户登录请求
     * @param request
     * @return
     */
    @RequestMapping("/login")
    @ResponseBody
    public String login(HttpServletRequest request){
        User user = new User();
        user.setId(1);
        user.setUserName("zhangsan");
        request.getSession().setAttribute("user", user);

        return "login success";

    }

    /**
     * 登录后才可以访问
     * @return
     */
    @RequestMapping("/center")
    @ResponseBody
    public String center(){

        return "see center message";
    }

    /**
     * 不登录也可以访问的请求
     * @return
     */
    @RequestMapping("/out")
    @ResponseBody
    public String out(){

        return "see out message";
    }

    /**
     * 如果用户没登录访问了需要登录的页面,跳转到该请求
     * @return
     */
    @RequestMapping("/error")
    @ResponseBody
    public String error(){

        return "error! you need login";
    }
}

第六章 SpringBoot使用Servlet(了解)

方式一:使用注解
-编写Servlet类,继承HttpServlet,按需要重写DoGet和DoPost方法
-在该类加上注解@WebServlet(urlPatterns = "/xxx")
-然后在入口类添加@ServletComponentScan(basePackages = "com.xxx.xxx")扫描Servlet所在包

@SpringBootApplication
@ServletComponentScan(basePackages = "com.learn.springboot.servlet")
public class Application {

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

}


@WebServlet(urlPatterns = "/myservlet")
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("***** MyServlet method *****");
        resp.getWriter().flush();
        resp.getWriter().close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

方式二:通过配置类注册组件
-编写servlet

public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("***** MyServlet2 method *****");
        resp.getWriter().flush();
        resp.getWriter().close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

-编写配置类,将servlet交给spring容器

@Configuration
public class ServletConfig {

    @Bean
    public ServletRegistrationBean<MyServlet> myServletRegistrationBean(){
        ServletRegistrationBean<MyServlet> myServletServletRegistrationBean
                = new ServletRegistrationBean<>(new MyServlet(), "/myservlet");

        return myServletServletRegistrationBean;
    }
}

第七章 SpringBoot使用Filter(了解)

方式一:

入口类:
@SpringBootApplication
@ServletComponentScan(basePackages = "com.learn.springboot.filter")
public class Application {

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

}

过滤器:
@WebFilter(urlPatterns = "/myfilter")
public class MyFilter implements Filter {


    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("this a filter");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    
}

方式二:
通过配置类注册组件

public class MyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("********filter2********");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}


@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean myFilterRegistrationBean(){
        FilterRegistrationBean<Filter> filterFilterRegistrationBean
                = new FilterRegistrationBean<>(new MyFilter());
        filterFilterRegistrationBean.addUrlPatterns("/user/*");

        return filterFilterRegistrationBean;
    }
}

@Controller
public class UserController {

    @RequestMapping("/user/detail")
    @ResponseBody
    public String userDetail(){
        return "this is user detail: ";
    }

    @RequestMapping("/other")
    @ResponseBody
    public String doOther(){
        return "this is other method ";
    }

}

注意拦截器的urlpatter要写一个*通配符

第八章 SpringBoot项目配置字符编码

方式一:
-编写Servlet返回中文

@WebServlet(urlPatterns = "/myservlet")
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");

        PrintWriter writer = resp.getWriter();

        writer.write("你好 hello world!");
        writer.flush();
        writer.close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

-编写配置类,配置filter

@Configuration
public class SystemConfig {

    @Bean
    public FilterRegistrationBean getCharacterEncodingFilter(){
        CharacterEncodingFilter characterEncodingFilter
                = new CharacterEncodingFilter("utf-8", true, true);

        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(characterEncodingFilter);
        filterRegistrationBean.addUrlPatterns("/*");

        return filterRegistrationBean;
    }
}

-在主文件扫描配置类

@SpringBootApplication
@ServletComponentScan(basePackages = "com.learn.springboot.servlet")
public class Application {

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

}

疑惑:这样这个filter根本没用,起作用的是setContentType方法而已啊。。。。把这个Filter注释了都行

方式二:
Servlet:

@WebServlet(urlPatterns = "/myservlet1")
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        

        PrintWriter writer = resp.getWriter();

        writer.write("你好 hello world!");
        writer.flush();
        writer.close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

入口:

@SpringBootApplication
@ServletComponentScan(basePackages = "com.learn.springboot.servlet")
public class Application {

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

}

主配置文件application.properties

server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
server.servlet.encoding.charset=utf-8

第九章 SpringBoot打包与部署

9.1 打war包

-程序入口类需扩展继承 SpringBootServletInitializer类并覆
盖 configure 方法

@SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) { SpringApplication.run(Application.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
//参数为当前 SpringBoot 启动类
return builder.sources(Application.class); }
}

-在 pom.xml 中添加(修改)打包方式为 war
<packaging>war</packaging>

-在 pom.xml 中配置 springboot 打包的插件(默认自动加)

<!--SpringBoot 打包插件--> <plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> </plugin>

-在 pom.xml 中配置将配置文件编译到类路径

<resource>
<!--源文件夹--> <directory>src/main/webapp</directory> <!--目标文件夹--> <targetPath>META-INF/resources</targetPath> <!--包含的文件-->
<includes>
<include>**/*.*</include> </includes>
</resource>
<!--mybatis 的 mapper.xml--> <resource>
<directory>src/main/java</directory> <includes>
<include>**/*.xml</include> </includes>
</resource>
<!--src/main/resources 下的所有配置文件编译到 classes 下面去--> <resource>
<directory>src/main/resources</directory> <includes>
<include>**/*.*</include> </includes>
</resource>

-在 pom.xml 的 build 标签下通过 finalName 指定打 war 包的名字

<!--指定打 war 包的名字--> 
<finalName>springboot</finalName>

通过 Maven package 命令打 war 包到 target 目录下

9.2 打jar包

image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png

9.3 Spring Boot 部署与运行方式总结

image.png

第十章 SpringBoot集成logback日志

image.png
image.png
image.png
image.png
image.png

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为 TRACE < DEBUG < INFO < WARN < ERROR < FATAL,
        如果 设置为 WARN,则低于 WARN 的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为 true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认 单位是毫秒。
        当 scan 为 true 时,此属性生效。默认的时间间隔为 1 分钟。 -->
<!-- debug:当此属性设置为 true 时,将打印出 logback 内部日志信息,实时查看 logback 运行状态。
        默认值为 false。通常不打印
-->
<configuration scan="true" scanPeriod="10 seconds">
    <!--输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志 appender 是为开发使用,只配置最底级别,控制台输出的日志级别是大 于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>debug</level>

        </filter>
        <encoder>
            <Pattern>%date [%-5p] [%thread] %logger{60} [%file : %line] %msg%n</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--<File>/home/log/stdout.log</File>-->
        <File>/Users/mac/Desktop/springboot-logback.log</File>
        <encoder>
            <pattern>%date [%-5p] %thread %logger{60} [%file : %line] %msg%n
            </pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 添加.gz 历史日志会启用压缩 大大缩小日志文件所占空间 -->
            <!--
            <fileNamePattern>/home/log/stdout.log.%d{yyyy-MM-dd}.log</fileNamePattern>
            -->
            <fileNamePattern>/Users/mac/Desktop/stdout.log.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory><!-- 保留30天日志-->
        </rollingPolicy>
    </appender>

    <logger name="com.learn.springboot.mapper" level="DEBUG"/>
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE"/>
    </root>
</configuration>

第十一章 SpringBoot集成Thymeleaf模板

11.1 认识Thymeleaf

image.png

11.2 SpringBoot集成Thymeleaf

在html标签里面添加xmlns:th="http://www.thymeleaf.org"
在h2标签使用th:text="$
"获取要显示的数据即可

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>message</title>
</head>
<body>
<h2 th:text="${msg}">展示要显示的信息:</h2>
</body>
</html>

11.3 关闭Thymeleaf页面缓存

1)在主配置文件关闭thymeleaf缓存

#设置thymeleaf模板引擎的前/后缀,可选
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

#设置thymeleaf模板引擎的缓存关闭
spring.thymeleaf.cache=false

2)配置configuration中为Update classes and resources
image.png

11.4 变量表达式

1)标准变量表达式
语法:${...}
说明:标准变量表达式用于访问容器(tomcat)上下文环境中的变量,功能和 EL 中的 ${} 相 同。Thymeleaf 中的变量表达式使用 ${变量名} 的方式获取 Controller 中 model 其中的数据

2)选择变量表达式(不推荐)
语法:*

说明:选择变量表达式,也叫星号变量表达式,使用 th:object 属性来绑定对象
选择表达式首先使用 th:object 来绑定后台传来的 User 对象,然后使用 * 来代表这个对 象,后面 {} 中的值是此对象中的属性。
选择变量表达式 *
是另一种类似于标准变量表达式 $ 表示变量的方法
选择变量表达式在执行时是在选择的对象上求解,而$
是在上下文的变量 Model 上求 解,这种写法比标准变量表达式繁琐,只需要大家了解即可

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>标准变量表达式:${}</h1>
用户姓名:<span th:text="${user.name}"></span><br/>
用户id:<span th:text="${user.id}"></span><br/>
用户年龄:<span th:text="${user.age}"></span><br/>

<h1>选择变量表达式()不推荐</h1>
<div th:object="${user}">
    用户编号:<span th:text="*{id}"></span><br/>
    name:<span th:text="*{name}"></span><br/>
    年龄:<span th:text="*{age}"></span><br/>

</div>
<h1>选择变量表达式和标准变量表达式混合使用(不推荐)</h1>
<div>
    用户编号:<span th:text="*{user.id}"></span><br/>
    name:<span th:text="*{user.name}"></span><br/>
    年龄:<span th:text="*{user.age}"></span><br/>
</div>
</body>
</html>

11.5 URL路径表达式

语法:
绝对路径 th:href="@{http://www.xxxx.com}"
相对路径 th:href="@{/xx1/xx2}"

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>URL路径表达式</title>
</head>
<body>
<h1>URL路径表达式:@{...}</h1>
<h2>a标签中的绝对路径(没有参数)</h2>
<a href="http://www.baidu.com">跳转到百度</a><br/>
<a th:href="@{http://www.baidu.com}">th路径表达式:跳转到百度</a><br/>
<a th:href="@{http://localhost:8080/user/detail}">th路径跳转到/user/detail</a><br/>
<a href="http://localhost:8080/user/detail">传统写法跳转到/user/detail</a><br/>

<h2>url路径表达式,相对路径 没有参数(实际开发中推荐使用的)</h2>
<a th:href="@{user/detail}">跳转到/user/detail</a>

<h2>绝对路径(带参数)</h2>
<a href="http://localhost:8080/test?username=lisi">绝对路径,带参数:/test,并带参数username</a><br/>
<a th:href="@{http://localhost:8080/test?username=wangwu}">路径表达式写法,带参数:/test,并带参数username</a><br/>

<h2>相对路径(带参数)</h2>
<a th:href="@{/test?username=lisi}">相对路径,带参数</a>

<h2>相对路径(带参数:后台获取的参数)</h2>
<a th:href="@{'/test?username='+${id}}">相对路径:获取后台参数值</a>

<h2>相对路径,带多个后台获取的参数</h2>
<a th:href="@{'/test1?username='+${username}+'&id='+${id}+'&age='+${age} }">带多个参数</a><br/>
<a th:href="@{/test1(id=${id},username=${username},age=${age})}">带多个参数 简单写法</a><br/>
<a th:href="@{'/test2/'+ ${id} }">请求路径为restful风格 test2</a><br/>
<a th:href="@{'/test3/'+ ${id} + '/' + ${username} }">请求路径为restful风格 test3</a>
<!--<a th:href="@{/test2/(${id}) }">请求路径为restful风格 第二种写法</a>-->
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" th:src="@{/js/jquery-1.7.2.min.js}"></script>
    <script type="text/javascript">
        $(function () {
            alert("----");
            alert($("#username").val());
        })
    </script>
</head>
<body>
<input type="text" id="username" value="999"/><br/>
<img th:src="@{/img/001.jpg }" width=500><br/>
</body>
</html>

11.6 常用属性

和普通的html一样,只是变成th:propertyname
name->th:name
一般在需要或取后台的数据才用th表达式,普通的写死一个值都是一样的作用。
常见属性
image.png

th:each的用法:
1)获取list集合的元素
控制层:

@Controller
public class UserController {

    @RequestMapping("/each/list")
    public String eachList(Model model){
        List<User> userList = new ArrayList<User>();
        for (int i = 0;i < 10;i++){
            User user = new User();
            user.setId(100 + i);
            user.setNick("张" + i);
            user.setPhone("1361234567" + i);
            user.setAddress("北京市大兴区" + i);
            userList.add(user);
        }
        model.addAttribute("userList",userList);
        return "each";
    }
}

页面:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--
    user 当前循环的对象变量名称
    userStat 当前循环对象状态的变量
    ${userList} 当前循环的集合
-->
<div th:each="user,userStat:${userList}">
    <span th:text="'index:'+${userStat.index}"></span>
    <span th:text="'count:'+${userStat.count}"></span>
    <span th:text="${user.id}"></span>
    <span th:text="${user.nick}"></span>
    <span th:text="${user.phone}"></span>
    <span th:text="${user.address}"></span><br/>

</div>

</body>
</html>

2)获取map集合的key和value
控制层:

@RequestMapping(value = "/each/map") public String eachMap(Model model) {
        Map<Integer,Object> userMaps = new HashMap<Integer, Object>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setId(i);
            user.setName("李四"+i);
            user.setPhone("1390000000"+i);
            user.setAddress("天津市"+i);
            user.setNick("李" +i);
            userMaps.put(i,user);
        }
        model.addAttribute("userMaps",userMaps);
        return "eachMap";
    }
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>循环遍历map集合</h1>
<div th:each="userMap,userMapStat:${userMaps}">
    <span th:text="${userMapStat.count}"></span>
    <span th:text="${userMapStat.index}"></span>
    <span th:text="${userMap.key}"></span>
    <span th:text="${userMap.value}"></span>
    <span th:text="${userMap.value.id}"></span>
    <span th:text="${userMap.value.name}"></span>
    <span th:text="${userMap.value.address}"></span>
    <span th:text="${userMap.value.nick}"></span>

</div>
</body>
</html>

3)获取数组
和list集合相同

4)复杂循环案例
image.png

控制层

    @RequestMapping(value = "/each/all") public String eachAll(Model model) {
        //list -> Map -> List -> User
        List<Map<Integer,List<User>>> myList = new ArrayList<Map<Integer, List<User>>>();
        for (int i = 0; i < 2; i++) {
            Map<Integer,List<User>> myMap = new HashMap<Integer,
                    List<User>>();
            for (int j = 0; j < 2; j++) {
                List<User> myUserList = new ArrayList<User>();
                for (int k = 0; k < 3; k++) {
                    User user = new User(); user.setId(k);
                    user.setName("张三"+k);
                    user.setPhone("1350000000"+k);
                    user.setAddress("广州市"+i);
                    myUserList.add(user);
                }
                myMap.put(j,myUserList);
            } myList.add(myMap);
        }
        model.addAttribute("myList",myList);
        return "eachAll";
    }

页面:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>循环遍历复杂集合:list->map->list->user</h3>
<div th:each="mylistMap:${myList}">
    <div th:each="myListMapObject:${mylistMap}">
        map集合的key:<span th:text="${myListMapObject.key}"></span>
        <div th:each="mapValue:${myListMapObject.value}">
            <span th:text="${mapValue.id}"></span>
            <span th:text="${mapValue.name}"></span>
            <span th:text="${mapValue.address}"></span>
            <span th:text="${mapValue.phone}"></span>
            <span th:text="${mapValue.nick}"></span>
        </div>

    </div>

</div>
</body>
</html>

11.7 条件判断if

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>条件判断</title>
</head>
<body>
<h2>th:if 用法:如果满足条件显示(执行,否则相反)</h2>
<div th:if="${sex eq 1}">
    男
</div>
<div th:if="${sex eq 0}">
    女
</div>

<h2>th:unless 用法:如果满足条件则不执行,否则执行,与if相反</h2>
<div th:unless="${sex eq 0}">
    女
</div>

<h1>th:switch th:case用法</h1>
<div th:switch="${productType}">
    <span th:case="0">产品0</span>
    <span th:case="1">产品1</span>
    <span th:case="*">无此产品</span>

</div>

</body>
</html>
@Controller
public class UserController {

    @RequestMapping("/condition")
    public String condition(Model model){
        model.addAttribute("sex", 1);
        model.addAttribute("flag", true);
        model.addAttribute("productType", 2);
        return "condition";

    }
}

11.8 th:line内敛表达式

th:inline 有三个取值类型 (text, javascript 和 none),值为 none 什么都不做,没有效果

内敛文本(th:inline=”text”)
内敛文本表达式不依赖于 html 标签,直接使用内敛表达式[[表达式]]即可获取动态数据,但 必须要求在父级标签上加 th:inline = “text”属性

内敛脚本(th:inline=”javascript”) th:inline=”javascript”在 js 代码中获取后台的动态数据

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>内敛表达式</title>
</head>
<body>
th:text取<div th:text="${data}"></div>

<h2>内敛文本: th:inline="text"</h2>
<div th:inline="text">
    数据:[[${data}]]
</div>

outside:数据:[[${data}]]


<h2>内敛脚本 th:inline="javascript"</h2>
<script type="text/javascript" th:inline="javascript">
    function showData() {
        alert([[${data}]]);
        alert("111");
    }

</script>

<button th:onclick="showData()">btn</button>
</body>
</html>

11.9 字面量

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>字面量</title>
</head>
<body>
<h1>文本字面量,用单引号'...'的字符串就是字面量</h1>
<a th:href="@{'/user/detail?sex='+${sex}}">查看性别</a><br/>
<span th:text="Hello"></span>

<h1>数字字面量</h1>
今年是<span th:text="2020"></span>年<br/>
</body>

<h1>boolean字面量</h1>
<div th:if="${flag}">
    执行成功
</div>
<div th:unless="${flag}">
    执行失败
</div>

<h1>null字面量</h1>
<span th:text="${user.name}"></span>
<!--<span th:text="${user2.id}">没有值</span>-->
<div th:if="${user2.id eq null}">
    user2.id为空
</div>

</html>


11.10 字符串拼接

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>splice</title>
</head>
<body>

<span th:text="'共'+${totalRows}+'条'+${totalPage}+'页,当前第'+${currentPage}+'页  ,首页 上一页 下一页 尾页'">共120条 12页, 当前第1页 </span>

<h1>使用更优雅的方式拼接字符串: |要拼接的字符串|</h1>
<span th:text="|共${totalRows}条 ${totalPage}页 当前第${currentPage}页 首页 上一页 下一页 尾页|">共120条 12页, 当前第1页 </span>

</body>
</html>

11.11 运算表达式

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>运算符</title>
</head>
<body>

<h2>三目运算符 布尔表达式?正确:错误</h2>
<div th:text="${sex eq 1}? 男 : 女"></div>

<h2>算术运算符</h2>

20+5=<span th:text="20+5"></span><br/>
20-5=<span th:text="20-5"></span><br/>
20*5=<span th:text="20*5"></span><br/>
20/5=<span th:text="20/5"></span><br/>
20%3=<span th:text="20%3"></span><br/>

<h2>关系比较</h2>
<div th:if=" 5 gt 2">
    5>2
</div>

<div th:if=" 2 lt 5">
    2<5
</div>
1<=1:<div th:if="1 le 1">
    真
</div>

<h2>相等判断</h2>
<span th:if="${sex == 1}">男</span>
<span th:if="${sex eq 0}">女</span>
<span th:if="${sex ne 1}">女</span>
</body>

</html>

11.12 表达式基本对象

模板引擎提供了一组内置的对象,这些内置的对象可以直接在模板中使用,这些对象由#号开始引用,我们比较常用的内置对象

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>index</title>

</head>
<body>
<h1>从session中获取值:</h1>
<div th:text="${#session.getAttribute('data')}"></div>
<!--<div th:text="${}"></div>-->
<div th:text="${#httpSession.getAttribute('data')}"></div>
<div th:text="${session.data}"></div>
<script type="text/javascript" th:inline="javascript">
    //http://localhost:8080/springboot/user/detail
    //获取协议名称
    var scheme = [[${#request.getScheme()}]];
    // alert(scheme);
    //获取服务器名称
    var serverName = [[${#request.getServerName()}]];
    // alert(serverName);
    //获取端口号
    var port = [[${#request.getServerPort()}]];
    // alert(port);
    //获取上下文根
    var contextPath = [[${#request.getContextPath()}]];

    //工程路径
    alert(scheme+'://'+serverName+':'+port+contextPath);


    var requestURL = [[${#httpServletRequest.requestURL}]];
    alert("requestURL:"+requestURL);
    var queryString = [[${#httpServletRequest.queryString}]];
    alert("queryString"+queryString);
    //完整路径
    alert(requestURL+'?'+queryString);
</script>
</body>


</html>

11.13 表达式功能对象

模板引擎提供的一组功能性内置对象,可以在模板中直接使用这些对象提供的功能方法 工作中常使用的数据类型,如集合,时间,数值,可以使用 Thymeleaf 的提供的功能性对象 来处理它们
官方手册:http://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html
image.png

第十二章 SpringBoot总结及综合案例

参考github上的cases 049 050 051 052