SpringBoot深入简出之篇四
使用SpringBoot做Web开发:
- 创建SpringBoot应用,选择我们需要的依赖场景模块;
- SpringBoot已经默认将这些场景配置好了,只需要在配置文件中指定少量配置就可以运行起来
- 编写我们自己的业务代码
自动配置原理
要想知道这个场景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
2、this.staticPathPattern = “/**”:访问当前项目的任何资源(静态资源的文件夹)
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
"/":当前项目的根路径
如下图所示具体位置:
由于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官方推荐的Thymeleaf;
- 引入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>
结果图
讲解一下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
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)
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=请输入用户名
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();
}
登录功能
开发期间模板引擎修改以后,要是实时生效两步走:
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>