SpringBoot深入简出之篇四

使用SpringBoot做Web开发:

  1. 创建SpringBoot应用,选择我们需要的依赖场景模块;
  2. SpringBoot已经默认将这些场景配置好了,只需要在配置文件中指定少量配置就可以运行起来
  3. 编写我们自己的业务代码

自动配置原理
要想知道这个场景SpringBoot帮我们配置了什么,能不能对其进修改,能修改的配置有哪些,能不能对这个配置文件进行扩展

xxxAutoConfiguration:帮我们给容器中自动配置组件;
xxxProperties:与场景配置文件中属性一一关联映射的配置类

SpringBoot对静态资源的映射规则

@ConfigurationProperties(
    prefix = "spring.resources",
    ignoreUnknownFields = false
)
public class ResourceProperties {
//可以设置和静态资源有关的参数,缓存时间等
public void addResourceHandlers(ResourceHandlerRegistry registry) {
            if (!this.resourceProperties.isAddMappings()) {
                logger.debug("Default resource handling disabled");
            } else {
                Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
                CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
                if (!registry.hasMappingForPattern("/webjars/**")) {
                    this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
                }

                String staticPathPattern = this.mvcProperties.getStaticPathPattern();
                if (!registry.hasMappingForPattern(staticPathPattern)) {
                    this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
                }

            }
        }

1、所有/webjars/**,都去classpath:/META-INF/resources/webjars/找资源(webjar就是以jar包的形式引入的静态资源)

<!-- jQuery依赖坐标 -->
   <dependency>
        <groupId>org.webjars</groupId>
        <artifactId>jquery</artifactId>
        <version>3.4.1</version>
    </dependency>

访问路径:http://localhost:8080/webjars/jquery/3.4.1/jquery.js

springboot textarea中的文本换行_静态资源


2、this.staticPathPattern = “/**”:访问当前项目的任何资源(静态资源的文件夹)

classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
"/":当前项目的根路径

如下图所示具体位置:

springboot textarea中的文本换行_静态资源_02


springboot textarea中的文本换行_spring_03


springboot textarea中的文本换行_spring_04


springboot textarea中的文本换行_jar_05


由于SpringBoot框架帮我们封装好了,“this.staticPathPattern = “/* *”:访问当前项目的任何资源(静态资源的文件夹)”都能够调用到项目中的静态资源。

3、欢迎首页;静态资源文件夹下的所有index.html页面也是被 **this.staticPathPattern = "/**映射
所以在访问项目的genlj根路径的时候也可以访问的静态资源中的HTML页面
4、所有的
/favicon.ico 都是在静态资源文件下找;

5、修改这些默认的静态资源路径

spring.resources.static-locations=classpath:/hello/, classpath:/yourfile/

模板引擎

JSP、Velocity、Freemarker、Thymeleaf

springboot textarea中的文本换行_spring_06


SpringBoot官方推荐的Thymeleaf;

  1. 引入Thymeleaf的maven依赖场景
<properties>
        <java.version>1.8</java.version>
        <!-- 设置Thymeleaf模板的版本 -->
        <thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
        <!-- 布局功能的支持程序 Thymeleaf3主程序 layout2以上版本 -->
        <!-- thymeleaf2 对应支持 layout1-->
        <thymeleaf-layout-dialect.verison>2.1.1</thymeleaf-layout-dialect.verison>
    </properties>
 <!-- Thymeleaf模板引擎依赖坐标 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

Thymeleaf 使用&语法

@ConfigurationProperties(
    prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
    private static final Charset DEFAULT_ENCODING;
    public static final String DEFAULT_PREFIX = "classpath:/templates/";
    public static final String DEFAULT_SUFFIX = ".html";
    private boolean checkTemplate = true;
    private boolean checkTemplateLocation = true;
    private String prefix = "classpath:/templates/";//前缀
    private String suffix = ".html";//后缀
    private String mode = "HTML";
    //只要我们把HTML页面放置classpath:/templates/文件夹下,Thymeleaf就会自动帮我们渲染

定义一个JavaBean

package cn.zdxh.lcy.demo03.model;

public class Person {
    private String name;
    private Integer age;

    public Person() {
        super();
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

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

定义一个@Controller类

package cn.zdxh.lcy.demo03.controller;

import cn.zdxh.lcy.demo03.model.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import sun.text.normalizer.NormalizerBase;

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

@Controller
public class Index {
    @ResponseBody
    @RequestMapping("/success")
    public String index() {
        return "index";
    }

    @RequestMapping("/index")
    public String success(Model model) {
    	//此处的Model 就像SpringMVC中的ViewAndModel 一样给View 层传递封装数据的域
        //classpath:/templates/index.html
        List<Person> list = new ArrayList<>();
        list.add(new Person("张三", 20));
        list.add(new Person("李四", 25));
        list.add(new Person("王五", 30));
        model.addAttribute("list", list);
        return "index";
    }
}

定义一个VIew层的index.html( classpath:/templates/index.html)

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>index页面</title>
</head>
<body>
    <h1>使用Thymeleaf模板</h1>
    <table th:if="${not #lists.isEmpty(list)}" border="1">
        <!-- 判断list集合是否有数据 -->
        <tr>
            <td>名字</td>
            <td>年龄</td>
        </tr>
        <tr th:each="person : ${list}"><!-- 遍历list集合的数据 -->
            <td th:text="${person.name}"></td><!-- 给标签设置文本 -->
            <td th:text="${person.age}"></td>
        </tr>
    </table>
</body>
</html>

结果图

springboot textarea中的文本换行_jar_07


讲解一下Thymeleaf 语法类型:

th:insert——片段包含(类似 jsp:include)
th:replace——片段替换
th:each——遍历集合(类似 c:forEach)
th:if——条件判断(类似 c:if)
th:switch + th:case——开关判断
th:object——变量声明(类似 c:set)
th:with
th:attr——任意属性修改
th:attrprepend——当前属性前面追加属性
th:attrappend——当前属性后面追加属性
th:value ——修改指定属性默认值
th:href——设置超链接
th:src
th:text——修改标签内容(转义特殊字符)
th:utext——(不转义特殊字符)
th:fragment——声明片段
th:remove——片段移除用

表达式语法:

Simple expressions:(表达式)
Variable Expressions: ${...}:获取变量值:OGNL
		1)、获取对象的属性,调用方法
				/*
				* Access to properties using the point (.). Equivalent to calling property getters.
				*/
				${person.father.name}//获取对象中的属性(以 . 的方式)
				/*
				* Access to properties can also be made by using brackets ([]) and writing
				* the name of the property as a variable or between single quotes.
				*/
				${person['father']['name']}获取对象中的属性(以 .[] 的方式)
				/*
				* If the object is a map, both dot and bracket syntax will be equivalent to
				* executing a call on its get(...) method.
				*/
				${countriesByCode.ES}
				${personsByName['Stephen Zucchini'].age}//获取map集合中的属性
				/*
				* Indexed access to arrays or collections is also performed with brackets,
				* writing the index without quotes.
				*/
				${personsArray[0].name}//获取数组中的属性
				/*
				* Methods can be called, even with arguments.
				*/
				${person.createCompleteName()}//调用对象中的方法
				${person.createCompleteNameWithSeparator('-')}//调用方法时可传参
		2)、使用内置的基本对象
				#ctx : the context object.(当前上下文)
				#vars: the context variables.(当前上下文变量)
				#locale : the context locale.(当前位置)
				#request : (only in Web Contexts) the HttpServletRequest object.(Request请求域)
				#response : (only in Web Contexts) the HttpServletResponse object.(Response响应域)
				#session : (only in Web Contexts) the HttpSession object.(Session回话域)
				#servletContext : (only in Web Contexts) the ServletContext object.
						${param.foo} // Retrieves a String[] with the values of request parameter 'foo'
						${param.size()}
						${param.isEmpty()}
						${param.containsKey('foo')}
		3)、内置的工具对象
				#execInfo : information about the template being processed.
				#messages : methods for obtaining externalized messages inside variables expressions, in the same way as they
				would be obtained using #{…} syntax.
				#uris : methods for escaping parts of URLs/URIs
				Page 20 of 106
				#conversions : methods for executing the configured conversion service (if any).
				#dates : methods for java.util.Date objects: formatting, component extraction, etc.
				#calendars : analogous to #dates , but for java.util.Calendar objects.
				#numbers : methods for formatting numeric objects.
				#strings : methods for String objects: contains, startsWith, prepending/appending, etc.
				#objects : methods for objects in general.
				#bools : methods for boolean evaluation.
				#arrays : methods for arrays.
				#lists : methods for lists.
				#sets : methods for sets.
				#maps : methods for maps.
				#aggregates : methods for creating aggregates on arrays or collections.
				#ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration)
				
Selection Variable Expressions: *{...}//选择表达式:功能上跟${}差不多
			补充:配合th:object="${session.user}"
						<div th:object="${session.user}">
							<p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
							<p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
							<p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
						</div>
Message Expressions: #{...}//获取国际化内容
Link URL Expressions: @{...}//定义URL超链接
			<!-- Will produce 'http://localhost:8080/gtvg/order/details?orderId=3' (plus rewriting) -->
			<a href="details.html" th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a>
			@{/order/process(execId=${execId},execType='FAST')}//多参数传递
Fragment Expressions: ~{...}//片段引用的表达式
			<div th:insert="~{commons :: main}">...</div>
Literals(字面量)
			Text literals: 'one text' , 'Another one!' ,…(文本)
			Number literals: 0 , 34 , 3.0 , 12.3 ,…(数字)
			Boolean literals: true , false(布尔)
			Null literal: null(设空)
			Literal tokens: one , sometext , main ,…
Text operations:(文本操作)
			String concatenation: +
			Literal substitutions: |The name is ${name}|
Arithmetic operations:(数学运算)
			Binary operators: + , - , * , / , %
			Minus sign (unary operator): -
Boolean operations:(布尔运算)
			Binary operators: and , or
			Boolean negation (unary operator): ! , not
Comparisons and equality:(比较运算)
			Comparators: > , < , >= , <= ( gt , lt , ge , le )
			Equality operators: == , != ( eq , ne )
Conditional operators:(条件运算)
			If-then: (if) ? (then)
			If-then-else: (if) ? (then) : (else)
			Default: (value) ?: (defaultvalue)

SpringMVC 自动配置
Spring Boot为Spring MVC提供自动配置,适用于大多数应用程序。

自动配置在Spring的默认值之上添加了以下功能:

1、Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

自动配置了ViewResolver(视图解析器:根据方法返回值得到视图对象(View),视图对象决定如何渲染(转发、重定向))

ContentNegotiatingViewResolver:组合所有的视图解析器;

如何定制:我们可以自己给容器中添加一个视图解析器;自动的将其组合起来;

2、Support for serving static resources, including support for WebJars (covered later in this document)).//静态资源文件夹路径,webjars

3、Automatic registration of Converter, GenericConverter, and Formatter beans.Support for

//Converter:转换器;public String hello(User user):类型转换使用Converter

//Formatter:格式化器;2019/11/30 === Date

springboot textarea中的文本换行_jar_08


4、HttpMessageConverters (covered later in this document).

HttpMessageConverters :SpringMVC用来转换Http请求和响应的;User(请求数据封装到JavaBean)—JSON(响应数据以JSON格式返回到View层)

HttpMessageConverters :是从容器中确定;获取所有的HttpMessageConverters ;

自己给容器中添加HttpMessageConverters ,只需将自己的组件注册到容器中(@bean、@Component)

5、Automatic registration of MessageCodesResolver (covered later in this document).//定义错误代码生成规则

6、Static index.html support.//静态首页访问

7、Custom Favicon support (covered later in this document).//favicon.ico图标 8、Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).//初始化WebDataBinder(web端数据绑定器:将请求的数据绑定到JavaBean中)

我们可以配置一个ConfigurableWebBindingInitializer 来替换默认的;(并且添加到容器中)

org.springframework.boot.autoconfigure.web:web中的所有自动配置场景
如果您想保留Spring Boot MVC功能并且想要添加其他 MVC配置(interceptors(拦截器), formatters(格式解析器), view controllers(视图控制器), and other features(其他功能)),您可以添加自己的@Configuration类类型 WebMvcConfigurer但不需要 @EnableWebMvc。如果您希望提供,或的 自定义实例RequestMappingHandlerMapping,则可以声明 实例以提供此类组件。RequestMappingHandlerAdapterExceptionHandlerExceptionResolverWebMvcRegistrationsAdapter

如果您想完全控制Spring MVC,可以添加自己的@Configuration 注释@EnableWebMvc。

扩展SpringMVC

<!-- 相当于在@Controller类中设置了一个hello请求路径返回的视图是index -->
<mvc:view-controller path="/hello" view-name="index" />
 <mvc:interceptors>
     <mvc:interceptor>
         <!-- 设置一个拦截器,把请求路径为/hello拦截下来-->
         <mvc:mapping path="/hello" />
         <!-- 拦截器处理bean,把/hello请求拦截下来转到下面指定的bean中处理后返回结果 -->
         <bean></bean>
     </mvc:interceptor> 
 </mvc:interceptors>

编写一个配置类(@Controller),是WebMvcConfigurationSupport 类型;不能标注 @EnableWebMVC;

这样做既保留了所有的自动配置功能,也能用我们自定义的配置

package cn.zdxh.lcy.demo03.config;

import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

//使用WebMvcConfigurationSupport可以来扩展SpringMVC的功能
@Controller
public class MyConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addViewControllers(ViewControllerRegistry registry) {
        //super.addViewControllers(registry);
        //设置当有/hello请求的时候就会转发到index视图页面
        registry.addViewController("hello").setViewName("index");
    }

原理:

1、WebMvcAutoConfiguration:使用SpringMVC的自动配置类

2、在做其他自动配置时会导入;@Import(EnableWebMvcConfiguration.class)

springboot textarea中的文本换行_jar_09


3、容器中所有的WebMvcConfigurer 都会一起起作用

4、我们的配置类因为注入了容器中,所以也会被EnableWebMvcConfiguration 调用

效果:SpringMVC的自动配置和我们的扩展配置都会起作用

全面接管SpringMVC(SpringBoot的web场景所有自动配置都会失效)
SpringBoot对SpringMVC的自动配置就失效了,所有都是我们自己配置(我们只需要在自自己的配置类上标注@EnableWebMVC);

失效的原因:
1、往主程序上标注@EnableWebMvc

@EnableWebMvc
@Controller
@SpringBootApplication
public class Demo03Application {

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

}

2、这是@EnableWebMvc 注解的源码

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})//导入了DelegatingWebMvcConfiguration 这个类
public @interface EnableWebMvc {
}

3、这是DelegatingWebMvcConfiguration 类的源码

@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {//而此处继承了WebMvcConfigurationSupport 这个类
    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();

4、SpringMVC的自动配置源码

@Configuration
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})//只有在没有WebMvcConfigurationSupport 这个类的时候才会生效
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {

5、也就是说只要标注了@EnableWebMvc 这个注解就会带来WebMvcConfigurationSupport 这个类,恰好SpringMVC 的自动配置类有这个判断条件下会失效
6、导入的WebMvcConfigurationSupport 只是SpringMVC 的基础功能

如何修改SpringBoot的默认配置
1、SpringBoot在自动配置组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如果有就用用户配置的,如果没有,才自动配置;如果有些组件有多个(ViewResolver)将用户配置的和自己默认的组合起来;
2、在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置

package cn.zdxh.lcy.demo03.config;

import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

//使用WebMvcConfigurationSupport可以来扩展SpringMVC的功能
@Controller
public class MyConfig extends WebMvcConfigurationSupport {
    @Override
    protected void addViewControllers(ViewControllerRegistry registry) {
        //super.addViewControllers(registry);
        //设置当有/hello请求的时候就会转发到index视图页面
        registry.addViewController("hello").setViewName("index");
    }

    //所有的WebMvcConfigurationSupport 组件都会一起其中作用
    public WebMvcConfigurationSupport webMvcConfigurationSupport() {
        WebMvcConfigurationSupport webMvc = new WebMvcConfigurationSupport(){
            @Override
            protected void addViewControllers(ViewControllerRegistry registry) {
                //super.addViewControllers(registry);
                //专门设置用户请求转发@Controller处理后的View层
                registry.addViewController("hello").setViewName("index");
                registry.addViewController("success").setViewName("index");
                registry.addViewController("index").setViewName("index");
            }
        };
        return webMvc;
    }
}

设置国际化
1、编写国际化配置文件
2、使用ResourceBundleMessageSource管理国际化资源文件
3、在页面使用fmt:message 去出国际化内容

使用步骤:
1、编写国际化配置文件,抽取页面需要显示的国际化消息
login.properties

login.password=密码:
login.password.tip=请输入密码
login.reset=重置
login.submit=登录
login.title=欢迎来到登录页面
login.username=用户名:
login.username.tip=请输入用户名

login_en_US.properties

login.password=password:
login.password.tip=please input your password
login.reset=reset
login.submit=sign in
login.title=Welcome to login page
login.username=username:
login.username.tip=please input your username

login_ch_CN.properties

login.password=密码:
login.password.tip=请输入密码
login.reset=重置
login.submit=登录
login.title=欢迎来到登录页面
login.username=用户名:
login.username.tip=请输入用户名

springboot textarea中的文本换行_spring_10


2、SpringBoot自动配置好了管理国际化资源文件

@MessageSourceAutoConfiguration 注解的源码

@Bean
    public MessageSource messageSource(MessageSourceProperties properties) {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        if (StringUtils.hasText(properties.getBasename())) {
//设置国际化资源文件的基础名(去掉语言国家代码的文件名)            messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename())));
        }

        if (properties.getEncoding() != null) {
            messageSource.setDefaultEncoding(properties.getEncoding().name());
        }

        messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
        Duration cacheDuration = properties.getCacheDuration();
        if (cacheDuration != null) {
            messageSource.setCacheMillis(cacheDuration.toMillis());
        }

        messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
        messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
        return messageSource;
    }

修改国际化默认配置

##设置login页面数据的国际化
spring.message.basename=i18n.login

3、去页面获取国际化的值
View层

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>index页面</title>
    <style type="text/css">
        #outer{
            width:750px;
        }
        span{
            color:#ff0000;
        }
        div{
            height:20px;
            margin-bottom:10px;
        }
        .main{
            margin:20px;
        }
        .ch{
            width:80px;
            float:left;
            text-align:right;
        }
        .ip{
            width:500px;
            float:left;
        }
        .ip>input{
            margin-right:20px;
        }
        #bt{
            margin-left:50px;
        }
        #bt>input{
            margin-right:30px;
        }
    </style>
</head>
<body>
<center>
    <h3 th:text="#{login.title}"></h3>
    <form action="" method="post">
        <table>
            <tr class="main">
                <td class="ch" th:text="#{login.username}"></td>
                <td><input type="text" name="username" th:placeholder="#{login.username.tip}" /></td>
            </tr>
            <tr class="main">
                <td class="ch" th:text="#{login.password}"></td>
                <td><input type="password" name="password1" th:placeholder="#{login.password.tip}" /></td>
            </tr>
            <tr class="main" style="margin:20px">
                <td id="anniu1" align="center"><input type="reset" th:value="#{login.reset}"/></td>
                <td id="anniu2" th:align="center"><input type="submit" th:value="#{login.submit}" /></td>
            </tr>
            <tr class="main" style="margin:20px">
                <!-- 设置请求连接并携带语言地区信息参数 -->
                <td id="anniu3" align="center"><a th:href="@{/index.html(language='zh_CN')}">中文</a></td>
                <td id="anniu4" th:align="center"><a th:href="@{/index.html(language='en_US')}">English</a></td>
            </tr>
        </table>
    </form>
</center>
</body>
</html>

组件工具类

package cn.zdxh.lcy.demo03.component;


import org.springframework.web.servlet.LocaleResolver;
import org.thymeleaf.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

/**
 * 可以在连接上携带区域语言信息
 */
public class MyLocaleResolver implements LocaleResolver {

    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        //获取用户选择的语言信息
        String language = request.getParameter("language");
        Locale locale = Locale.getDefault();
        //如果用户没有选择语言信息,系统会选择默认的语言信息
        if (!StringUtils.isEmpty(language)){
            String[] arr = language.split("_");
            //修改默认配置的语言和地区
            locale = new Locale(arr[0], arr[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {

    }
}

Controller层

@Bean//把自己设置组件添加容器中
    public LocaleResolver localeResolver() {
        return new MyLocaleResolver();
    }

springboot textarea中的文本换行_jar_11


springboot textarea中的文本换行_spring_12


登录功能

开发期间模板引擎修改以后,要是实时生效两步走:

1、禁用模板引擎缓存

##警用Thymeleaf模板引擎的缓存
spring.thymeleaf.cache=false

2、页面修改完成以后Ctrl + F9:重新编译(idea快捷键)

登录错误消息的显示

<!-- 先判断报错消息是否存在 -->
<p style="color: red" th:text="${error}" th:if="${not #strings.isEmpty(error)}"></p>

拦截器进行用户登陆检查
1、用户登录处理@Controller

@RequestMapping("/user/login")
    public String userLogin(@RequestParam("username")String username, @RequestParam("password") String password, Model model, HttpSession session){
        String str = null;
        Map<String, Object> map = new HashMap<>();
        if (!StringUtils.isEmpty(username) && password.equals("123456")){
            map.put("username", username);
            map.put("password", password);
            model.addAttribute("username", username);
            model.addAttribute("password", password);
            //设置session域作为判别用户的操作权限
            session.setAttribute("loginUser", username);
            str = "redirect:/main.html";//用户登录成功
        } else {
            str = "index";
            map.put("error", "用户名或密码输入错误!");
            model.addAttribute("error", "用户名或密码输入错误!");
        }
        return str;
    }

2、编写拦截器处理方法

package cn.zdxh.lcy.demo03.component;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.thymeleaf.util.StringUtils;

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

/**
 * 登录检查,没有登录的用户不用进入系统主页
 */
public class LoginHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取用户的操作权限
        Object username = request.getSession().getAttribute("loginUser");
        if(username == null){//用户名不为空则获得操作系统权限
            request.setAttribute("error", "您没有获得操作权限,请先登录!");
            //拦截不通过把路径转发到login页面
            request.getRequestDispatcher("/").forward(request, response);
            return false;
        } else {
        	//拦截通过
            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 {

    }
}

3、把拦截器组件注册到容器中(只有这样才会生效)

//注册拦截器
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        //super.addInterceptors(registry);
        //静态资源:*.css,*.js
        //SpringBoot已经做好了静态资源映射
        //设置拦截的请求范围(addPathPatterns)和不拦截的请求范围(excludePathPatterns)
        registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/", "index", "/user/login");


    }

CRUD-员工列表
实验要求:
1、RestfulCRUD:CRUF满足Rest风格;
URI:/资源名称/资源标识 HTTP请求方式来区分对资源CRUD(增删查改)

普通CRUD(uri来区分操作)

RestfulCRUD

查询

getEmp

emp—GET

添加

addEmp

emp—POST

修改

updateEmp

emp/{id}—PUT

删除

deleteEmp

emp/{id}—DELETE

2、实验的请求架构:

实验功能

请求URI

请求方式

查询所有员工

emps

GET

查询单个员工

emp/{id}

GET

来到添加页面

emp

GET

添加员工

emp

POST

来到修改页面(查出员工进行信息回显)

emp/{id}

GET

修改员工

emp

PUT

删除员工

emp/{id}

DELETE

Thymeleaf公共页面元素抽取

1、抽取公共片段(copy为自定义的片段名)
<div th:fragment="copy">
	© 2011 The Good Thymes Virtual Grocery
</div>
2、引入公共片段(在footer页面中引入片段名为copy的片段)
<div th:insert="~{footer :: copy}"></div>

~{templatename::selector}:模板名 :: 选择器
~{templatename::fragmentname}:模板名 ::  片段名

3、默认效果:
insert的功能片段在div标签中
如果使用th:insert等属性进行引入,可以不用写~{};
行内写法:[[~{}]](转义),[(~{})](不转义)

三种引入功能片段的th属性:
th:insert: 将公共片段整个插入到声明引入的元素中
th:replace: 将声明引入的元素替换为公共片段
th:include: 将被引入的片段的内容包含进这个标签中

1、提取公共片段
<footer th:fragment="copy">
	© 2011 The Good Thymes Virtual Grocery
</footer>

2、引入公共片段
<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>

3、效果:
<div>
	<footer>
		© 2011 The Good Thymes Virtual Grocery
	</footer>
</div>
<footer>
	© 2011 The Good Thymes Virtual Grocery
</footer>
<div>
	© 2011 The Good Thymes Virtual Grocery
</div>