03.视图层开发

视图层开发

1.简介

使用SpringBoot步骤:

1)创建SpringBoot应用,选择我们需要的模块开发

2)SpringBoot已经将这些场景配置好了。只需要在配置文件中配置少量配置就可以运行起来了

3)编写业务代码

自动配置需要理解:

这个场景SpringBoot帮我们配置了什么?能不能修改?能修改哪些配置,能不能扩展??

1
2
xxxxAutoConfiguration:帮我们给容器中自动配置组件
xxxxProperties:配置类来封装配置文件的内容

2.SpringBoot对静态资源的映射规则

1
2
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {}

1)所有/webjars/**,都去 classpath:/META-INF/resources/webjars/找资源

​ webjars:以jar包的方式引入静态资源 https://www.webjars.org/

1539496359453

localhost:8080/webjars/jquery/3.3.1-1/jquery.js

1539496541648

1
2
3
4
5
6
<!--jQuery-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1-1</version>
</dependency>

2) “/**” 访问当前项目的任何资源(静态资源的文件夹)resources就是类路径下的根目录

1
2
3
4
5
6

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

localhost:8080/jquery.js == 去静态文件夹下的jquery.js

3)欢迎页,静态资源文件夹下的所有index.html;被”/**”映射

localhost:8080

4)所有的**/favicon.ico 都是在静态资源文件夹下找

依然可以在application.properties文件夹下进行自动指定

1
2
spring.resources.static-locations=classpath:/ooyhao/,
# 但是自己指定了的话,原有的静态文件路径就不再生效了

3.模板引擎

JSP、Velocity、Freemarker、Thymeleaf

SpringBoot推荐的Thymeleaf;语法更简单,功能更强大;**thymeleaf 官网 **

1、引入thymeleaf

1
2
3
4
5
6
7
8
9
10
11
12
13
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
3.0.9
</dependency>
切换thymeleaf版本 (可以切换,但是现在已经是最新的版本了)
<properties>
<!-- 布局功能的支持程序 -->
<!-- thymeleaf3主程序 layout2以上版本 -->
<!-- thymeleaf2 layout1-->
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
</properties>

2、Thymeleaf使用

1
2
3
4
5
6
7
8
9
10
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {

private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;

public static final String DEFAULT_PREFIX = "classpath:/templates/";

public static final String DEFAULT_SUFFIX = ".html";
//前后缀,只要把html页面放在classpath:/templates/,thymeleaf就能自动渲染了
}

只要我们把HTML页面放在classpath:/templates/,thymeleaf就能自动渲染;

SpringBoot 的自动配置

1
2
3
4
5
# 关于 thymeleaf 的配置信息这里使用默认配置即可(下面均为默认配置)
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.mode=HTML
spring.thymeleaf.suffix=.html
spring.thymeleaf.encoding=utf-8

导入thymeleaf的名称空间,并使用thymeleaf语法;

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<!--导入thymeleaf的名称空间-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>成功!</h1>
<!--th:text 将div里面的文本内容设置为 -->
<div th:text="${hello}">这是显示欢迎信息</div>
</body>
</html>

3、语法规则

1.th:text;改变当前元素里面的文本内容;

​ th:任意html属性;来替换原生属性的值

1
2
3
<h1>你好</h1> 
使用th:text 输出:<h1>你好</h1>
使用th:utext输出:你好(加粗)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<table border="1">
<tr>
<td>图书编号</td>
<td>图书名称</td>
<td>图书作者</td>
<td>图书价格</td>
</tr>
<tr th:each="book : ${books}">
<td th:text="${book.id}"></td>
<td th:text="${book.name}"></td>
<td th:text="${book.author}"></td>
<td th:text="${book.price}"></td>
</tr>
</table>

2.表达式?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Simple expressions:(表达式语法)
Variable Expressions: ${...}:获取变量值(OGNL);
1.获取对象的属性、调用方法
2.使用内置的基本对象:${session.foo}
3.内置的一些工具对象:

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;
@{/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)
Special tokens:
No-Operation: _

示例 html文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<!--th:text 将div里面的文本内容设置为传递过来的-->
<div th:text="${hello}">这是显示欢迎信息</div>
<div th:utext="${hello}">这是显示欢迎信息</div>
<!--th:each每次遍历都会生成当前这个标签:3个h4-->
<h4 th:text="${user}" th:each="user:${users}"></h4>
<hr/>
<h4>
<span th:each="user:${users}">[[${user}]]</span>
</h4>
<hr/>
</body>
</html>

controller文件:

1
2
3
4
5
6
7
8
9
@Controller
public class HelloController {
@GetMapping("/hello")
public String hello(Map<String,Object> map){
map.put("hello","<h1>你好</h1>");
map.put("users", Arrays.asList("张三","李四","王五"));
return "message";
}
}

效果图:

1539506449400

4、Springmvc自动配置

https://docs.spring.io/spring-boot/docs/2.0.5.RELEASE/reference/htmlsingle/#boot-features-spring-mvc

1.Spring MVC Auto-configuration

SpringBoot自动配置好了SpringMVC

以下是SpringBoot对SpringMVC的默认配置:

Spring Boot provides auto-configuration for Spring MVC that works well with mostapplications.

The auto-configuration adds the following features on top of Spring’s defaults:

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

    • 自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染,是请求转发,还是重定向)
    • ContentNegotiatingViewResolver:组合所有的视图解析器的
    • 如何定制:我们可以自己给容器添加一个视图解析器;自动的将其组合进来、
  • Support for serving static resources, including support for WebJars (coveredlater in this document)).

    • 静态资源文件jar与webjars
  • Automatic registration of Converter, GenericConverter, and Formatter beans.

    • 自动注册了Converter, GenericConverter, and Formatter

    • Converter:转换器;public String hello(User user):类型转换组件

    • Formatter:格式化器:2017-12-17 ==> Date

    • 自己添加格式化器,我们只需要放到容器中即可

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      If you need to add or customize converters, you can use Spring Boot’s HttpMessageConverters class, as shown in the following listing:

      import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
      import org.springframework.context.annotation.*;
      import org.springframework.http.converter.*;

      @Configuration
      public class MyConfiguration {

      @Bean
      public HttpMessageConverters customConverters() {
      HttpMessageConverter<?> additional = ...
      HttpMessageConverter<?> another = ...
      return new HttpMessageConverters(additional, another);
      }
      }
  • Support for HttpMessageConverters (coveredlater in this document).

    • HttpMessageConverters:SpringMVC用来装换http请求和相应的;User–Json

    • HttpMessageConverters是从容器中确定的,获得所有的HttpMessageConverter;

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

  • Automatic registration of MessageCodesResolver (coveredlater in this document). 定义错误代码生成规则。

  • Static index.html support. 静态资源首页

  • Custom Favicon support (covered later in thisdocument). 图标

  • Automatic use of a ConfigurableWebBindingInitializer bean (coveredlater in this document).

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

    初始化web数据绑定器WebDataBinder

    请求数据 == > JavaBean

    org.springframework.boot.autoconfigure.web :web的所有自动配置场景。

If you want to keep Spring Boot MVC features and you want to add additionalMVC configuration (interceptors, formatters, viewcontrollers, and other features), you can add your own @Configuration class of typeWebMvcConfigurer but without @EnableWebMvc. If you wish to provide custominstances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, orExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapterinstance to provide such components.

If you want to take complete control of Spring MVC, you can add your own @Configurationannotated with @EnableWebMvc.

2.扩展SpringMVC

1
2
3
4
5
6
7
<mvc:view-controller path="/hello" view-name="success"/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/hello"/>
<bean></bean>
</mvc:interceptor>
</mvc:interceptors>

编写一个配置类(@Configuration)是WebMvcConfigurer类型,不能标注@EnableWebMvc

既保留了所有的自动配置,也能用我们扩展的配置。

1
2
3
4
5
6
7
8
9
@Configuration
public class MyMvcConfig implements WebMvcConfigurer{

@Override
public void addViewControllers(ViewControllerRegistry registry){
//浏览器发送 /hello请求,来到message页面
registry.addViewController("/ooyhao").setViewName("message");
}
}

原理:

1)WebMvcAutoConfiguration是springmvc的自动配置类

2)新版本使用的是WebMvcConfigurer,而不是WebMvcConfigurerAdapter,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {


@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();

//从容器中获取所有的WebMvcConfigurer
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
//一个参考实现,将所有的WebMvcConfigurer相关的配置都一起调用起来
//@Override
//public void addViewControllers(ViewControllerRegistry registry) {
//for (WebMvcConfigurer delegate : this.delegates) {
//delegate.addViewControllers(registry);
//}
//}
}
}
}

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

4)我们的配置类也会被调用。

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

3.全面接管SpringMvc

SpringBoot对SpringMVC的自动配置不需要了。所有的配置都是我们自己配置。所有的SpringMVC自动配置都失效了。

我们需要在配置类上添加@EnableWebMvc即可

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* @author ooyhao
*/
@EnableWebMvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer{

@Override
public void addViewControllers(ViewControllerRegistry registry){
//浏览器发送 /hello请求,来到message页面
registry.addViewController("/ooyhao").setViewName("message");
}
}

原理:

1)

1
2
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {}

2)

1
2
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

3)

1
2
3
4
5
6
7
8
9
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
//容器中没有这个组件的时候,这个自动配置类才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {

4)@EnableWebMvc将WebMvcConfigurationSupport组件导入进来,

5)导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能

5.如何修改SpringBoot的默认配置

模式:

1)SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean,@Component)如果有就用用户配置的,如果没有,才自动配置,如果有些组件可以有多个(例如:ViewResolver)将用户配置的和默认的组合起来

2)在SpringBoot中会有非常多的*Configuration帮助我们扩展配置。

3)在springboot中也会用很多的xxxCustomizer帮助我们进行定制配置

6.RestfulCRUD

1.默认访问首页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//所有的webMvcConfigurer组件都会一起起作用
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer(){
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//注意:urlPath=RequestMapping(value)
// viewName=return "";(原handler中返回的视图名)
registry.addViewController("/").setViewName("login");
registry.addViewController("/index").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
}
};
}

// 或者是
@RequestMapping(value = {"/","/index.html"})
public String index(){
return "index";
}

2.国际化

1)编写国际化配置文件

2)使用ResourceBundleMessageSource管理国际化资源文件

3)在页面使用fmt:message取出国际化内容

以前使用需要1,2,3.现在使用SpringBoot,

步骤:

1.编写国际化配置文件,抽取页面需要显示的国际化消息

1539529250871

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

自动配置源码:

1
2
3
4
public class MessageSourceAutoConfiguration {
private String basename = "messages";
//我们的配置文件可以直接放在类路径下叫message.properties;
}

3.去页面获取国际化的值

解决中文乱码,file–>other setting–>default setting

1539530134934

1539530414992

1539530494142

实现了国际化效果

1
spring.messages.basename=i18n.login

html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<body class="text-center">
<form class="form-signin" action="dashboard.html">
<img class="mb-4" th:src="@{/asserts/img/bootstrap-solid.svg}" src="asserts/img/bootstrap-solid.svg" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
<label class="sr-only" th:text="#{login.username}">Username</label>
<input type="text" class="form-control" placeholder="Username" th:placeholder="#{login.username}" required="" autofocus="">
<label class="sr-only" th:text="#{login.password}">Password</label>
<input type="password" class="form-control" th:placeholder="#{login.password}" placeholder="Password" required="">
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me">[[#{login.remember}]]
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">Sign in</button>
<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
<a class="btn btn-sm">中文</a>
<a class="btn btn-sm">English</a>
</form>

</body>

效果:根据浏览器语言设置的信息切换国际化;

原理:国际化locale(区域信息对象);LocaleResolver(获取区域信息对象)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
if (this.mvcProperties
.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}

//默认的就是根据请求头带来的区域信息获取Locale进行国际化

4.点击链接切换国际化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 可以在连接上携带区域信息
*/
public class MyLocaleResolver implements LocaleResolver{

@Override
public Locale resolveLocale(HttpServletRequest request) {
//解析区域信息
String l = request.getParameter("l");
Locale locale = Locale.getDefault();
if(!StringUtils.isEmpty(l)){
String[] strings = l.split("_");
locale = new Locale(strings[0],strings[1]);
}
return locale;
}

@Override
public void setLocale(HttpServletRequest request,
HttpServletResponse response,
Locale locale) {}
}

加入到SpringBoot容器中

1
2
3
4
5
 //添加组件
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}

3.登录

在开发期间,模板引擎页面修改以后, 要实时生效:

1)禁用模板引擎的缓存

1
2
#禁用缓存
spring.thymeleaf.cache=false

2)页面修改完成以后ctrl+f9,重新编译

登录错误消息显示

1
2
<!--判断-->
<p style="color:red;" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>

1539616214325

4.拦截器进行登录检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 登录检查
*/
public class LoginHandlerInterceptor implements HandlerInterceptor {
/**
* 目标方法执行之前
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws ServletException, IOException {
String loginUser = (String) request.getSession().getAttribute("loginUser");
if(loginUser != null){
return true;
}
request.setAttribute("msg","没有权限,请登录");
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}
}

如何添加拦截器:

​ 1.编写一个自定义拦截器类并实现HandlerInterceptor接口;编写相应的逻辑

​ 2.在webmvc配置类中配置配置注册拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//@EnableWebMvc  //不要完全接管SpringMVC的功能
@Configuration
public class MyMvcConfig implements WebMvcConfigurer{

@Override
public void addViewControllers(ViewControllerRegistry registry){
//浏览器发送 /hello请求,来到message页面
registry.addViewController("/ooyhao").setViewName("message");
}

//所有的webMvcConfigurer组件都会一起起作用
@Bean
public WebMvcConfigurer webMvcConfigurer(){
return new WebMvcConfigurer(){
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//注意:urlPath=RequestMapping(value)
// viewName=return "";(原handler中返回的视图名)
registry.addViewController("/").setViewName("login");
registry.addViewController("/index").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
registry.addViewController("/main.html").setViewName("dashboard");
}

//添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {

registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**") //拦截任意请求
.excludePathPatterns("/index.html","/","index","/user/login","/webjars/**","/asserts/**") //排除拦截请求
//静态资源不用排除,SpringBoot已经做好了静态资源映射,拦截器处理是可以不用考虑静态资源
;
}
};
}

//添加组件国际化
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
}

5.CRUD员工列表

1.RestfulCRUD

URI:/资源名称/资源标识 HTTP请求方式区分对资源CRUD操作

普通CRUD RestfulCRUD
查询 getEmp emp–GET
添加 addEmp?xxx emp–POST
修改 update?id=xxx&xxx=xxx emp/{id}–PUT
删除 deleteEmp?id=1 emp/{id}–DELETE

2.实验的请求架构

请求的URI 请求方式
查询所有员工 emps GET
查询某个员工 emp/1 GET
来到添加页面 emp GET
添加员工 emp POST
来到修改页面(查询员工信息回显) emp/1 GET
修改员工 emp PUT
删除员工 emp/1 DELETE

3.员工列表

1.thymeleaf公共页面元素抽取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1.抽取公共片段,利用th:fragment
<div th:fragment="copy">
&copy; 2011 The Good Thymes Virtual Grocery
</div>

2.引入公共片段
<div th:insert="~{footer :: copy}"></div>
~{templatename::selector}:模板名::选择器
<div th:replace="~{dashboard::topbar}"></div>
~{templatename::fragmentname}:模板名::片段名
<div th:replace="~{dashboard::#sidebar}"></div>
3.默认效果
insert的动能片段在div标签中
如果使用th:insert等属性进行引入,可以不用写~{}:
行内写法可以加上:[[~{}]],[(~{})]

三种引入功能片段的th属性:

1.th:insert:将公共片段整个插入到整个声明引入的元素中

2.replace:将声明引入的元素替换成公共片段

3.include:被引入的片段的内容包含进这个标签中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<footer th:fragment="copy">
&copy; 2011 The Good Thymes Virtual Grocery
</footer>

<!--引入方式-->
<body>
<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
</body>

<!--效果-->
<div>
<footer>
&copy; 2011 The Good Thymes Virtual Grocery
</footer>
</div>

<footer>
&copy; 2011 The Good Thymes Virtual Grocery
</footer>

<div>
&copy; 2011 The Good Thymes Virtual Grocery
</div>

再引入片段的时候传入参数:

在抽取的部分进行定义判断 th:class=”${activeUri == ‘emps’?’nav-link active’:’nav-link’}”

1
2
3
4
5
6
7
8
9
10
11
<a class="nav-link active" href="#"
th:class="${activeUri == 'emps'?'nav-link active':'nav-link'}"
th:href="@{/emps}">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-users">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
<circle cx="9" cy="7" r="4"></circle>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
</svg>
员工管理
</a>

在引入的地方进行变量赋值

1
<div th:replace="~{commons/bar::#sidebar(activeUri='emps')}"></div>
2.添加页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<form>
<div class="form-group">
<label>LastName</label>
<input type="text" class="form-control" placeholder="zhangsan">
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" placeholder="zhangsan@atguigu.com">
</div>
<div class="form-group">
<label>Gender</label><br/>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="gender" value="1">
<label class="form-check-label"></label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="gender" value="0">
<label class="form-check-label"></label>
</div>
</div>
<div class="form-group">
<label>department</label>
<select class="form-control">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</select>
</div>
<div class="form-group">
<label>Birth</label>
<input type="text" class="form-control" placeholder="zhangsan">
</div>
<button type="submit" class="btn btn-primary">添加</button>
</form>

员工添加提交的数据格式不对:生日—日期

2017-12-12;2017/12/12;2017.12.12

日期的格式化:SpringMVC将页面提交的值需要转换为指定的类型

默认日期是按照斜线/方式;在配置文件中自定义时间格式:

1
2
#自定义时间格式
spring.mvc.date-format=yyyy-MM-dd
3.更新与修改的页面复用,以及如何提交PUT请求

请求除get,post请求之外的请求,使用一个隐藏域,name=”_method”.value=”put”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!--需要区分是员工修改还是员工添加-->
<!--
1.springmvc中配置HiddenHttpMethodFilter
2.页面创建一个post变单
3.创建一个input项,name必须是_method
-->
<form th:action="@{/emp}" th:method="post" method="post">
<input type="hidden" name="_mathod" value="put" th:if="${emp!=null}" >
<input type="hidden" name="id" th:value="${emp!= null}?${emp.id}">
<div class="form-group">
<label>LastName</label>
<input name="lastName" type="text" class="form-control" placeholder="zhangsan" th:value="${emp!=null}?${emp.lastName}">
</div>
<div class="form-group">
<label>Email</label>
<input name="email" type="email" class="form-control" placeholder="zhangsan@atguigu.com" th:value="${emp!=null}?${emp.email}">
</div>
<div class="form-group">
<label>Gender</label><br/>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="gender" value="1" th:checked="${emp!=null}?${emp.gender == 1}">
<label class="form-check-label"></label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="gender" value="0" th:checked="${emp!=null}?${emp.gender == 0} ">
<label class="form-check-label"></label>
</div>
</div>
<div class="form-group">
<label>department</label>
<select class="form-control" name="department.id" >
<!--提交的是部门id-->
<option th:each="dept:${depts}" th:text="${dept.departmentName}" th:value="${dept.id}" th:selected="${emp!=null}?${emp.department.id} == ${dept.id}"></option>
</select>
</div>
<div class="form-group">
<label>Birth</label>
<input type="text" class="form-control" name="birth" placeholder="zhangsan" th:value="${emp!=null}?${#dates.format(emp.birth, 'yyyy-MM-dd HH:mm')}">
</div>
<button type="submit" class="btn btn-primary" th:text="${emp!=null}?'修改':'添加'">添加</button>
</form>

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×