资源引入
自定义首页
控制器里面写
@RequestMapping ( "/" )
public String index ( )
{
return "login" ;
}
或者配置类里面写
package jane. test. jane. config;
import org. springframework. context. annotation. Configuration;
import org. springframework. web. servlet. config. annotation. EnableWebMvc;
import org. springframework. web. servlet. config. annotation. ViewControllerRegistry;
import org. springframework. web. servlet. config. annotation. WebMvcConfigurerAdapter;
@Configuration
@EnableWebMvc
public class MyConfig extends WebMvcConfigurerAdapter
{
@Override
public void addViewControllers ( ViewControllerRegistry registry)
{
registry. addViewController ( "/jane" ) . setViewName ( "success" ) ;
}
@Bean
public WebMvcConfigurerAdapter webMvcConfigurerAdapter ( )
{
WebMvcConfigurerAdapter adapter= new WebMvcConfigurerAdapter ( )
{
@Override
public void addViewControllers ( ViewControllerRegistry registry)
{
registry. addViewController ( "/" ) . setViewName ( "login" ) ;
registry. addViewController ( "index.html" ) . setViewName ( "login" ) ;
}
} ;
return adapter;
}
}
引擎模板引入资源
使用th: href= "@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" 引入资源
在以后项目名发生变化的时候也能相应地进行改变
< ! -- Bootstrap core CSS -- >
< link href= "asserts/css/bootstrap.min.css" th: href= "@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel= "stylesheet" >
< ! -- Custom styles for this template -- >
< link href= "asserts/css/signin.css" th: href= "@{/asserts/css/signin.css}" rel= "stylesheet" >
国际化
在以前我们在MVC里面编写国际化功能的时候, 还算有点麻烦:
1. 编写国际化配置文件
2. 使用ResourceBundleMessageSource管理国际化资源文件
3. 然后在页面中使用fmt: message来取出国际化内容
但现在不一样了, 我们使用SpringBoot差不多只需要编写国际化配置文件就行了
编写国际化配置文件,抽取页面需要显示的国际化消息
SpringBoot自动配置好了管理国际化资源文件的组件;
@Configuration
@ConditionalOnMissingBean ( value = MessageSource. class , search = SearchStrategy. CURRENT)
@AutoConfigureOrder ( Ordered. HIGHEST_PRECEDENCE)
@Conditional ( ResourceBundleCondition. class )
@EnableConfigurationProperties
@ConfigurationProperties ( prefix = "spring.messages" )
public class MessageSourceAutoConfiguration {
private static final Resource[ ] NO_RESOURCES = { } ;
private String basename = "messages" ;
去页面获取国际化的值;
< ! DOCTYPE html>
< html lang= "en" xmlns: th= "http://www.thymeleaf.org" >
< head>
< meta http- equiv= "Content-Type" content= "text/html; charset=UTF-8" >
< meta name= "viewport" content= "width=device-width, initial-scale=1, shrink-to-fit=no" >
< meta name= "description" content= "" >
< meta name= "author" content= "" >
< link rel= "shortcut icon" href= "/favicon.ico" / >
< link rel= "bookmark" href= "/favicon.ico" / >
< title> Signin Template for Bootstrap< / title>
< ! -- Bootstrap core CSS -- >
< link href= "asserts/css/bootstrap.min.css" th: href= "@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel= "stylesheet" >
< ! -- Custom styles for this template -- >
< link href= "asserts/css/signin.css" th: href= "@{/asserts/css/signin.css}" rel= "stylesheet" >
< / head>
< ! -- 使用th: href= "@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" 引入资源
在以后项目名发生变化的时候也能相应地进行改变-- >
< body class = "text-center" >
< form class = "form-signin" action= "dashboard.html" >
< img class = "mb-4" th: href= "@{/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" th: placeholder= "#{login.username}" placeholder= "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" th: href= "@{/index.html(l='zh_CN')}" > 中文< / a>
< a class = "btn btn-sm" th: href= "@{/index.html(l='en_US')}" > English< / a>
< / form>
< / body>
< / html>
但是我们需要实现的是点击实现中英文的切换
这个得需要了解它的原理才行:
在国际化里面有些重要的对象:
国际化Locale(区域信息对象);LocaleResolver(获取区域信息对象);
在SpringBoot里面也对它们进行了默认的配置
可以看出, 在我们没有自己配置这个组件的时候,
默认的就是根据请求头带来的区域信息获取Locale进行国际化
@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;
}
现在我们需要自己点击来进行切换, 所以要换成自己的国际化LocaleResolver
然后加入到容器中
package jane. test. component;
import org. springframework. util. StringUtils;
import org. springframework. web. servlet. LocaleResolver;
import javax. servlet. http. HttpServletRequest;
import javax. servlet. http. HttpServletResponse;
import java. util. Locale;
public class MyLocalResolver implements LocaleResolver
{
@Override
public Locale resolveLocale ( HttpServletRequest request)
{
String l = request. getParameter ( "l" ) ;
Locale local= Locale. getDefault ( ) ;
if ( ! StringUtils. isEmpty ( l) )
{
String[ ] split = l. split ( "_" ) ;
local = new Locale ( split[ 0 ] , split[ 1 ] ) ;
}
return local;
}
@Override
public void setLocale ( HttpServletRequest request, HttpServletResponse response, Locale locale)
{
}
}
登录和拦截器
现在的麻烦是, 每次我修改页面的代码, 或者修改模板引擎里面的页面代码,
在浏览器访问的时候都是访问旧的代码, 修改后的代码无法访问
解决方案:
在配置文件里面禁用掉模板引擎的缓存
#禁用模板引擎缓存
spring. thymeleaf. cache= false
idea在运行项目的时候是不进行自动编译的
所以在修改页面后要进行重新编译, 快捷键是ctrl+ F9
package jane. test. controller;
import org. springframework. stereotype. Controller;
import org. springframework. util. StringUtils;
import org. springframework. web. bind. annotation. *;
import javax. servlet. http. HttpSession;
import java. util. Map;
@Controller
public class LoginController
{
@PostMapping ( value = "/user/login" )
public String login ( @RequestParam ( "username" ) String username,
@RequestParam ( "password" ) String password, Map< String, Object> map,
HttpSession session)
{
if ( ! StringUtils. isEmpty ( username) && "1234" . equals ( password) )
{
session. setAttribute ( "loginUser" , username) ;
return "redirect:/main.html" ;
}
else
{
map. put ( "msg" , "用户名和密码不正确" ) ;
return "login" ;
}
}
}
上面为了防止表单重新提交使用了重定向, 但是这样谁都可以访问主页了, 所以需要做拦截器进行拦截
registry. addViewController ( "main.html" ) . setViewName ( "dashboard" ) ;
package jane. test. component;
import org. springframework. web. servlet. HandlerInterceptor;
import org. springframework. web. servlet. ModelAndView;
import javax. servlet. http. HttpServletRequest;
import javax. servlet. http. HttpServletResponse;
public class MyLoginHandlerInterceptor implements HandlerInterceptor
{
@Override
public boolean preHandle ( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
Object user = request. getSession ( ) . getAttribute ( "loginUser" ) ;
if ( user== null)
{
request. setAttribute ( "msg" , "没有权限访问这个页面" ) ;
request. getRequestDispatcher ( "/index.html" ) . 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
{
}
}
然后将这个拦截器加入到容器里面
package jane. test. config;
import jane. test. component. MyLocalResolver;
import jane. test. component. MyLoginHandlerInterceptor;
import org. springframework. context. annotation. Bean;
import org. springframework. context. annotation. Configuration;
import org. springframework. web. servlet. LocaleResolver;
import org. springframework. web. servlet. config. annotation. InterceptorRegistry;
import org. springframework. web. servlet. config. annotation. ViewControllerRegistry;
import org. springframework. web. servlet. config. annotation. WebMvcConfigurerAdapter;
@Configuration
public class MyConfig extends WebMvcConfigurerAdapter
{
@Override
public void addViewControllers ( ViewControllerRegistry registry)
{
registry. addViewController ( "/jane" ) . setViewName ( "success" ) ;
}
@Bean
public WebMvcConfigurerAdapter webMvcConfigurerAdapter ( )
{
WebMvcConfigurerAdapter adapter= new WebMvcConfigurerAdapter ( )
{
@Override
public void addViewControllers ( ViewControllerRegistry registry)
{
registry. addViewController ( "/" ) . setViewName ( "login" ) ;
registry. addViewController ( "index.html" ) . setViewName ( "login" ) ;
registry. addViewController ( "main.html" ) . setViewName ( "dashboard" ) ;
}
@Override
public void addInterceptors ( InterceptorRegistry registry)
{
registry. addInterceptor ( new MyLoginHandlerInterceptor ( ) )
. addPathPatterns ( "/**" )
. excludePathPatterns ( "/index.html" , "/" , "/user/login" ) ;
}
} ;
return adapter;
}
@Bean
public LocaleResolver localeResolver ( )
{
return new MyLocalResolver ( ) ;
}
}
CRUD
RestfulCRUD风格
我们的CRUD要满足Rest风格的, 叫RestfulCRUD
就是URI: / 资源名称/ 资源标识 HTTP请求方式区分对资源CRUD操作
RestfulCRUD和普通CRUD的区别
普通CRUD(uri来区分操作) RestfulCRUD 查询 getEmp emp—GET 添加 addEmp?xxx emp—POST 修改 updateEmp?id=xxx&xxx=xx emp/{id}—PUT 删除 deleteEmp?id=1 emp/{id}—DELETE
所以我们的请求方式大概如下:
请求URI 请求方式 查询所有员工 emps GET 查询某个员工(来到修改页面) emp/1 GET 来到添加页面 emp GET 添加员工 emp POST 来到修改页面(查出员工进行信息回显) emp/1 GET 修改员工 emp PUT 删除员工 emp/1 DELETE
抽取thymeleaf公共页面元素
如何使用, 在官网有详细的说明, 下面我们来看下
官网详细说明
Say we want to add a standard copyright footer to all our grocery pages,
so we create a / WEB- INF/ templates/ footer. html file containing this code:
首先抽取公共片段
< div th: fragment= "copy" >
& copy; 2011 The Good Thymes Virtual Grocery
< / div>
然后在别的地方引用:
< div th: insert= "~{footer :: copy}" > < / div>
解释: footer是引用的模板的所在文件, copy是自定义的片段的名称
引入的写法有两种:
{ templatename: : selector} :模板名: : 选择器, 比如id选择器就使用#
~ { templatename: : fragmentname} : 模板名: : 片段名
Note that th: insert expects a fragment expression ( ~ { . . . } ) ,
which is an expression that results in a fragment.
In the above example though, which is a non- complex fragment expression,
the ( ~ { , } ) enclosing is completely optional,
so the code above would be equivalent to:
这里简单地引入, ~ { } 可以省略, 写成
< div th: insert= "footer :: copy" > < / div>
三种引入公共片段的th属性
th: insert:将公共片段整个插入到声明引入的元素中
th: replace:将声明引入的元素替换为公共片段
th: include:将被引入的片段的内容包含进这个标签中
官网就有个很好的例子
Difference between th: insert and th: replace ( and th: include)
And what is the difference between th: insert and th: replace ( and th: include, not recommended since 3.0 ) ?
th: insert is the simplest: it will simply insert the specified fragment as the body of its host tag.
th: replace actually replaces its host tag with the specified fragment.
th: include is similar to th: insert, but instead of inserting the fragment it only inserts the contents of this fragment.
So an HTML fragment like this :
< footer th: fragment= "copy" >
& copy; 2011 The Good Thymes Virtual Grocery
< / footer>
…included three times in host < div> tags, like this :
< body>
. . .
< div th: insert= "footer :: copy" > < / div>
< div th: replace= "footer :: copy" > < / div>
< div th: include= "footer :: copy" > < / div>
< / body>
…will result in:
< 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>
< / body>
引入带有参数的公共片段
Parameterizable fragment signatures
比如定义公共片段的时候在里面使用两个参数onevar, twovar:
< div th: fragment= "frag (onevar,twovar)" >
< p th: text= "${onevar} + ' - ' + ${twovar}" > . . . </ p>
< / div>
在引用的时候:
his requires the use of one of these two syntaxes to call the fragment from th: insert or th: replace:
只能使用这两种引用方式
< div th: replace= "::frag (${value1},${value2})" > . . . </ div>
< div th: replace= "::frag (onevar=${value1},twovar=${value2})" > . . . </ div>
如果你定义的公共片段没有定义参数名:
Fragment local variables without fragment arguments
< div th: fragment= "frag" >
. . .
< / div>
We could use the second syntax specified above to call them ( and only the second one) :
我们也可以使用第二种方式来引用, 只能使用第二种:
< div th: replace= "::frag (onevar=${value1},twovar=${value2})" >
增删改查
和常规套路差不多, 可以注意一下删除员工的方法
因为需要将请求方式改成delete的, 所以要增加一个form表单的
但是每一个员都增加form表单, 这个页面就超级多form表单的了
所以使用的是ajax的方式来提交表单
< td>
< a class = "btn btn-sm btn-primary" th: href= "@{/emp/}+${emp.id}" > 编辑< / a>
< button th: attr= "del_uri=@{/emp/}+${emp.id}" class = "btn btn-sm btn-danger deleteBtn" > 删除< / button>
< / td>
< form id= "deleteEmpForm" method= "post" >
< input type= "hidden" name= "_method" value= "delete" / >
< / form>
< script>
$( ".deleteBtn" ) . click ( function ( ) {
$( "#deleteEmpForm" ) . attr ( "action" , $( this ) . attr ( "del_uri" ) ) . submit ( ) ;
return false ;
} ) ;
< / script>
package jane. test. controller;
import jane. test. dao. DepartmentDao;
import jane. test. dao. EmployeeDao;
import jane. test. entities. Department;
import jane. test. entities. Employee;
import org. springframework. beans. factory. annotation. Autowired;
import org. springframework. stereotype. Controller;
import org. springframework. ui. Model;
import org. springframework. web. bind. annotation. *;
import java. util. Collection;
@Controller
public class EmployeeController
{
@Autowired
EmployeeDao employeeDao;
@Autowired
DepartmentDao departmentDao;
@GetMapping ( "/emps" )
public String list ( Model model)
{
Collection< Employee> employees = employeeDao. getAll ( ) ;
model. addAttribute ( "emps" , employees) ;
return "emp/list" ;
}
@GetMapping ( "/emp" )
public String toAddPage ( Model model) {
Collection< Department> departments = departmentDao. getDepartments ( ) ;
model. addAttribute ( "depts" , departments) ;
return "emp/add" ;
}
@PostMapping ( "/emp" )
public String addEmp ( Employee employee) {
System. out. println ( "保存的员工信息:" + employee) ;
employeeDao. save ( employee) ;
return "redirect:/emps" ;
}
@GetMapping ( "/emp/{id}" )
public String toEditPage ( @PathVariable ( "id" ) Integer id, Model model) {
Employee employee = employeeDao. get ( id) ;
model. addAttribute ( "emp" , employee) ;
Collection< Department> departments = departmentDao. getDepartments ( ) ;
model. addAttribute ( "depts" , departments) ;
return "emp/add" ;
}
@PutMapping ( "/emp" )
public String updateEmployee ( Employee employee) {
System. out. println ( "修改的员工数据:" + employee) ;
employeeDao. save ( employee) ;
return "redirect:/emps" ;
}
@DeleteMapping ( "/emp/{id}" )
public String deleteEmployee ( @PathVariable ( "id" ) Integer id) {
employeeDao. delete ( id) ;
return "redirect:/emps" ;
}
}
< ! DOCTYPE html>
< ! -- saved from url= ( 0052 ) http: / / getbootstrap. com/ docs/ 4.0 / examples/ dashboard/ -- >
< html lang= "en" xmlns: th= "http://www.thymeleaf.org" >
< head>
< meta http- equiv= "Content-Type" content= "text/html; charset=UTF-8" >
< meta name= "viewport" content= "width=device-width, initial-scale=1, shrink-to-fit=no" >
< meta name= "description" content= "" >
< meta name= "author" content= "" >
< title> Dashboard Template for Bootstrap< / title>
< ! -- Bootstrap core CSS -- >
< link href= "asserts/css/bootstrap.min.css" th: href= "@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel= "stylesheet" >
< ! -- Custom styles for this template -- >
< link href= "asserts/css/dashboard.css" th: href= "@{/asserts/css/dashboard.css}" rel= "stylesheet" >
< style type= "text/css" >
@- webkit- keyframes chartjs- render- animation {
from {
opacity: 0.99
}
to {
opacity: 1
}
}
@keyframes chartjs- render- animation {
from {
opacity: 0.99
}
to {
opacity: 1
}
}
. chartjs- render- monitor {
- webkit- animation: chartjs- render- animation 0.001 s;
animation: chartjs- render- animation 0.001 s;
}
< / style>
< / head>
< body>
< ! -- 引入抽取的topbar-- >
< ! -- 模板名:会使用thymeleaf的前后缀配置规则进行解析-- >
< div th: replace= "commons/bar::topbar" > < / div>
< div class = "container-fluid" >
< div class = "row" >
< ! -- 引入侧边栏-- >
< div th: replace= "commons/bar::#sidebar(activeUri='emps')" > < / div>
< main role= "main" class = "col-md-9 ml-sm-auto col-lg-10 pt-3 px-4" >
< h2> < a class = "btn btn-sm btn-success" href= "emp" th: href= "@{/emp}" > 员工添加< / a> < / h2>
< div class = "table-responsive" >
< table class = "table table-striped table-sm" >
< thead>
< tr>
< th> #< / th>
< th> lastName< / th>
< th> email< / th>
< th> gender< / th>
< th> department< / th>
< th> birth< / th>
< th> 操作< / th>
< / tr>
< / thead>
< tbody>
< tr th: each= "emp:${emps}" >
< td th: text= "${emp.id}" > < / td>
< td> [ [ ${ emp. lastName} ] ] < / td>
< td th: text= "${emp.email}" > < / td>
< td th: text= "${emp.gender}==0?'女':'男'" > < / td>
< td th: text= "${emp.department.departmentName}" > < / td>
< td th: text= "${#dates.format(emp.birth, 'yyyy-MM-dd HH:mm')}" > < / td>
< td>
< a class = "btn btn-sm btn-primary" th: href= "@{/emp/}+${emp.id}" > 编辑< / a>
< button th: attr= "del_uri=@{/emp/}+${emp.id}" class = "btn btn-sm btn-danger deleteBtn" > 删除< / button>
< / td>
< / tr>
< / tbody>
< / table>
< / div>
< / main>
< form id= "deleteEmpForm" method= "post" >
< input type= "hidden" name= "_method" value= "delete" / >
< / form>
< / div>
< / div>
< ! -- Bootstrap core JavaScript
== == == == == == == == == == == == == == == == == == == == == == == == == -- >
< ! -- Placed at the end of the document so the pages load faster -- >
< script type= "text/javascript" src= "asserts/js/jquery-3.2.1.slim.min.js" th: src= "@{/webjars/jquery/3.3.1/jquery.js}" > < / script>
< script type= "text/javascript" src= "asserts/js/popper.min.js" th: src= "@{/webjars/popper.js/1.11.1/dist/popper.js}" > < / script>
< script type= "text/javascript" src= "asserts/js/bootstrap.min.js" th: src= "@{/webjars/bootstrap/4.0.0/js/bootstrap.js}" > < / script>
< ! -- Icons -- >
< script type= "text/javascript" src= "asserts/js/feather.min.js" th: src= "@{/asserts/js/feather.min.js}" > < / script>
< script>
feather. replace ( )
< / script>
< script>
$( ".deleteBtn" ) . click ( function ( ) {
$( "#deleteEmpForm" ) . attr ( "action" , $( this ) . attr ( "del_uri" ) ) . submit ( ) ;
return false ;
} ) ;
< / script>
< / body>
< / html>
< ! DOCTYPE html>
< ! -- saved from url= ( 0052 ) http: / / getbootstrap. com/ docs/ 4.0 / examples/ dashboard/ -- >
< html lang= "en" xmlns: th= "http://www.thymeleaf.org" >
< head>
< meta http- equiv= "Content-Type" content= "text/html; charset=UTF-8" >
< meta name= "viewport" content= "width=device-width, initial-scale=1, shrink-to-fit=no" >
< meta name= "description" content= "" >
< meta name= "author" content= "" >
< title> Dashboard Template for Bootstrap< / title>
< ! -- Bootstrap core CSS -- >
< link href= "asserts/css/bootstrap.min.css" th: href= "@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel= "stylesheet" >
< ! -- Custom styles for this template -- >
< link href= "asserts/css/dashboard.css" th: href= "@{/asserts/css/dashboard.css}" rel= "stylesheet" >
< style type= "text/css" >
@- webkit- keyframes chartjs- render- animation {
from {
opacity: 0.99
}
to {
opacity: 1
}
}
@keyframes chartjs- render- animation {
from {
opacity: 0.99
}
to {
opacity: 1
}
}
. chartjs- render- monitor {
- webkit- animation: chartjs- render- animation 0.001 s;
animation: chartjs- render- animation 0.001 s;
}
< / style>
< / head>
< body>
< ! -- 引入抽取的topbar-- >
< ! -- 模板名:会使用thymeleaf的前后缀配置规则进行解析-- >
< div th: replace= "commons/bar::topbar" > < / div>
< div class = "container-fluid" >
< div class = "row" >
< ! -- 引入侧边栏-- >
< div th: replace= "commons/bar::#sidebar(activeUri='emps')" > < / div>
< main role= "main" class = "col-md-9 ml-sm-auto col-lg-10 pt-3 px-4" >
< ! -- 需要区分是员工修改还是添加;-- >
< form th: action= "@{/emp}" method= "post" >
< ! -- 发送put请求修改员工数据-- >
< ! --
1 、SpringMVC中配置HiddenHttpMethodFilter; (SpringBoot自动配置好的)
2 、页面创建一个post表单
3 、创建一个input项,name= "_method" ; 值就是我们指定的请求方式
-- >
< input type= "hidden" name= "_method" value= "put" th: if = "${emp!=null}" / >
< input type= "hidden" name= "id" th: if = "${emp!=null}" th: value= "${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@qq.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>
< ! -- 提交的是部门的id-- >
< select class = "form-control" name= "department.id" >
< option th: selected= "${emp!=null}?${dept.id == emp.department.id}" th: value= "${dept.id}" th: each= "dept:${depts}" th: text= "${dept.departmentName}" > 1 < / option>
< / select>
< / div>
< div class = "form-group" >
< label> Birth< / label>
< input name= "birth" type= "text" class = "form-control" 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>
< / main>
< / div>
< / div>
< ! -- Bootstrap core JavaScript
== == == == == == == == == == == == == == == == == == == == == == == == == -- >
< ! -- Placed at the end of the document so the pages load faster -- >
< script type= "text/javascript" src= "asserts/js/jquery-3.2.1.slim.min.js" th: src= "@{/webjars/jquery/3.3.1/jquery.js}" > < / script>
< script type= "text/javascript" src= "asserts/js/popper.min.js" th: src= "@{/webjars/popper.js/1.11.1/dist/popper.js}" > < / script>
< script type= "text/javascript" src= "asserts/js/bootstrap.min.js" th: src= "@{/webjars/bootstrap/4.0.0/js/bootstrap.js}" > < / script>
< ! -- Icons -- >
< script type= "text/javascript" src= "asserts/js/feather.min.js" th: src= "@{/asserts/js/feather.min.js}" > < / script>
< script>
feather. replace ( )
< / script>
< / body>
< / html>