SpringBoot-03-開發Web專案
5 SpringBoot開發web專案
5.1 靜態資源對映
靜態資源對映規則
-
在開發一個web專案中,我們不可避免的要使用到許多靜態資源,如CSS、JS等,那麼SpringBoot是怎麼處理這些資源的呢?
-
官方文件
-
官方文件告訴了我們SpringBoot中預設存放靜態資源的幾個位置,
/static
、/public
、/resources
、/META-INF/resources
。或者是配置檔案中指定的位置 -
除了這些常規手段之外,還提到了一種特殊的靜態資源
webjars
,所有的webjars
會被對映到路徑/webjars/**
上-
什麼是
webjars
?- 按照
jar
- 按照
-
示例
-
引入maven依賴
<dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.5.1</version> </dependency>
-
訪問測試
紅色框出來的檔案都會被對映到url
/webjars
下
-
-
5.2 首頁處理
-
官方文件給出的說明是,SpringBoot會在靜態資源的目錄下查詢一個叫
index.html
index
的模板 -
使用循序
index.html
>index
模板
5.3 ThymeLeaf
模板引擎
-
Web開發的模板引擎是為了使使用者介面與業務資料(內容)分離而產生的,它可以生成特定格式的文件,用於網站的模板引擎就會生成一個標準的HTML文件。
-
我們之前使用的jsp就是一種模板引擎,不過他已經過時了,我們就不在使用它了。
-
這張圖可以告訴你模板引擎怎麼工作的
-
SpringBoot原生支援的模板引擎:FreeMaker、Groovy、Thymeleaf、Mustache,其中官方建議我們使用Thymeleaf
Thymeleaf簡介
-
Thymeleaf是用來開發Web和獨立環境專案的伺服器端的Java模版引擎
-
Thymeleaf與SpringMVC的檢視技術,及SpringBoot的自動化配置整合非常完美,幾乎沒有任何成本,你只用關注Thymeleaf的語法即可。
-
優點
- 動靜結合:Thymeleaf 在有網路和無網路的環境下皆可執行,即它可以讓美工在瀏覽器檢視頁面的靜態效果,也可以讓程式設計師在伺服器檢視帶資料的動態頁面效果。這是由於它支援 html 原型,然後在 html 標籤裡增加額外的屬性來達到模板+資料的展示方式。瀏覽器解釋 html 時會忽略未定義的標籤屬性,所以 thymeleaf 的模板可以靜態地執行;當有資料返回到頁面時,Thymeleaf 標籤會動態地替換掉靜態內容,使頁面動態顯示。
- 開箱即用:它提供標準和spring標準兩種方言,可以直接套用模板實現JSTL、 OGNL表示式效果,避免每套模板、改jstl、改標籤的困擾。同時開發人員也可以擴充套件和建立自定義的方言。
- 多方言支援:Thymeleaf 提供spring標準方言和一個與 SpringMVC 完美整合的可選模組,可以快速的實現表單繫結、屬性編輯器、國際化等功能。
- SpringBoot完美整合,SpringBoot提供了Thymeleaf的預設配置,並且為Thymeleaf設定了檢視解析器,我們可以像以前操作jsp一樣來操作Thymeleaf。程式碼幾乎沒有任何區別,就是在模板語法上有區別
-
如何使用
-
匯入Thymeleaf啟動器
<!--thymeleaf--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
-
把模板檔案放到template資料夾下
-
語法
參考:https://www.cnblogs.com/jiangbei/p/8462294.html
-
建立HTML,這樣的話才能在上下文中使用
th
標籤<html xmlns:th="http://www.thymeleaf.org">
-
變數
${variable}
,*{...}
<p th:text="'Hello!, '+${name}+'!'">World</p> <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> <!--等價於--> <div> <p>Name: <span th:text="${session.user.firstName}">Sebastian</span>.</p> <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p> <p>Nationality: <span th:text="${session.user.nationality}">Saturn</span>.</p> </div>
-
連結表示式
@{…}
<a href="details.html" th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a>
-
文字替換,在替換時不能進行條件判斷
<span th:text="'Welcome to our application, ' + ${user.name} + '!'"/>
-
運算子
- 算數運算子:
+
,-
,*
,/
,%
- 邏輯運算子:
>
,<
,>=
,<=
,==
,!=
- 條件運算子:
- If-then: (if) ? (then)
- If-then-else: (if) ? (then) : (else)
- Default: (value) ?: (defaultvalue)
- 算數運算子:
-
條件選擇
th:if
,th:unless
,th:switch
<a th:href="@{/login}" th:if=${session.user == null}>Login</a> <a th:href="@{/login}" th:unless=${session.user != null}>Login</a> <div th:switch="${user.role}"> <p th:case="'admin'">User is an administrator</p> <p th:case="#{roles.manager}">User is a manager</p> <p th:case="*">User is some other thing</p> </div>
-
迴圈
th:each
<table> <tr> <th>ID</th> <th>NAME</th> <th>AGE</th> </tr> <tr th:each="emp : ${empList}"> <td th:text="${emp.id}">1</td> <td th:text="${emp.name}">海</td> <td th:text="${emp.age}">18</td> </tr> </table>
5.4 配置SpringMVC
預設配置下的SpringMVC
- 包含
ContentNegotiatingViewResolver
和BeanNameViewResolver
- 映射了靜態資源路徑,包括支援了
Webjars
- 自動註冊了一些型別轉換器和格式轉化器
- 支援 Http 訊息轉換和 錯誤程式碼定製
- 支援靜態首頁
- 初始化資料繫結器(自動繫結資料到JavaBean上)
如何擴充套件SpringMVC
-
官方文件
-
翻譯
- 如果你在預設的配置上增加額外的配置,實現介面
WebMvcConfigurer
,只給這個類加上@Configuration
註解,千萬別用@EnableWebMvc
` - 如果想定製一些元件,就實現
WebMvcRegistrations
介面 - 如果想全面接管SpringMVC,就給你的配置類同時加上
@Configuration
和@EnableWebMvc
- 如果你在預設的配置上增加額外的配置,實現介面
-
原始碼分析
-
我們找到
WebMvcAutoConfiguration
,這個是SpringMVC的自動配置類。可以看到這個類的有這麼一個生效條件@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
,這個註解的意思是,當不存在WebMvcConfigurationSupport
這個類的時候,預設配置才會生效 -
下面我們再來看
@EnableWebMvc
的原始碼,可以看見他引入了一個叫DelegatingWebMvcConfiguration
的類。字面意思就是託管WebMVC的自動配置。 -
再深入檢視原始碼之後,這個
DelegatingWebMvcConfiguration
實際上繼承了WebMvcConfigurationSupport
,這也就是說為什麼我們在擴充套件SpringMVC的時候,不要加上@EnableWebMvc
` 的註解
-
5.5 i18n國際化
-
SpringBoot支援本地化訊息用於迎合不同使用者的語言需求
-
預設情況下,SpringBoot會在
classpath
下查詢訊息資源包,也可以通過配置檔案指定位置 -
示例
-
在
resources
目錄下建立i18n
資料夾,IDEA會自動識別這個資料夾為國際化的檔案 -
在SpringBoot中配置國際化資源路徑
spring: messages: basename: i18n.message
-
建立中文的配置檔案和英文的配置檔案
-
zh_CN
alert=請登入 loginBtn=登入 password=密碼 remember=記住密碼(不建議在公共電腦上勾選) username=使用者名稱
-
en_US
alert=Please sign in loginBtn=SIGN IN password=Password remember=Remember Me (not recommended to set on public computers) username=username
-
-
在首頁中使用
-
效果展示
-
-
原始碼分析
-
在
WebMvcAutoConfiguration
中有關於選擇 本地資源的內容,具體邏輯如下- 先判斷是否總是使用配置的語言環境
- 如果不是的話,則根據請求頭中的
Accept-Language
解析使用什麼樣的語言資源
-
5.6 上手操作
準備工作
-
把前端模板放到該放的地方
-
匯入Maven依賴
<dependencies> <!--web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--資料庫--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <!--配置工具--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
-
實體類
@Data @AllArgsConstructor @NoArgsConstructor @Repository public class Department { private int id; private String name; }
@Data @AllArgsConstructor @NoArgsConstructor @Repository public class Employee { private int id; private String name; private String email; private int gender; private Department department; private Date birth; }
-
配置資料庫連線資訊
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: 123456 url: jdbc:mysql://localhost:3306/springboot?serverTimezone=GMT%2B8&useSSL=true&useUnicode=true&characterEncoding=utf8
MyBatis整合
-
配置MyBatis
mybatis: mapper-locations: classpath:mybatis/mapper/*.xml type-aliases-package: com.pbx.pojo
-
mapper
-
DepartmentMapper.java
@Mapper @Repository public interface DepartmentMapper { List<Department> getDepartmentList(); Department getDepartmentById(@Param("departmentID") int id); int countByDepartmentId(@Param("departmentID")int id); int updateDepartment(Department department); int deleteDepartment(@Param("departmentID") int id); int insertDepartment(Department department); }
-
DepartmentMapper.xml
<mapper namespace="com.pbx.mapper.DepartmentMapper"> <select id="getDepartmentList" resultType="com.pbx.pojo.Department"> select * from springboot.department </select> <select id="getDepartmentById" resultType="com.pbx.pojo.Department"> select * from springboot.department where id = #{departmentID} </select> <select id="countByDepartmentId" resultType="java.lang.Integer"> SELECT COUNT(id) num FROM springboot.employee WHERE department = #{departmentID} </select> <update id="updateDepartment" parameterType="com.pbx.pojo.Department"> update springboot.department set name = #{name} where id = #{id}; </update> <delete id="deleteDepartment"> delete from springboot.department where id = #{departmentID}; </delete> <insert id="insertDepartment" parameterType="com.pbx.pojo.Department"> insert into springboot.department (id, name) values (#{id}, #{name}) </insert> </mapper>
-
EmployeeMapper.java
@Mapper @Repository public interface EmployeeMapper { List<Employee> getEmployeeList(); Employee getOneById(@Param("employeeID") int id); int addEmployee(Employee employee); int updateEmployee(Employee employee); int deleteEmployee(int id); }
-
EmployeeMapper.xml
<mapper namespace="com.pbx.mapper.EmployeeMapper"> <!--因為實體類的欄位和資料庫的欄位不一致,所以要配置這resultMap和parameterMap--> <resultMap id="resultMap" type="com.pbx.pojo.Employee"> <!--有association之後就要配置所有屬性的對映--> <result property="id" column="id"/> <result property="name" column="last_name"/> <result property="email" column="email"/> <result property="gender" column="gender"/> <result property="birth" column="birth"/> <association property="department" javaType="com.pbx.pojo.Department"> <result property="id" column="did"/> <result property="name" column="dname"/> </association> </resultMap> <select id="getEmployeeList" resultMap="resultMap"> select e.id, e.last_name, e.email, e.gender, e.department, e.birth, d.id did, d.name dname from springboot.employee e, springboot.department d where e.department = d.id </select> <select id="getOneById" resultMap="resultMap"> select e.id, e.last_name, e.email, e.gender, e.department, e.birth, d.id did, d.name dname from springboot.employee e, springboot.department d where e.id = #{employeeID} and e.department = d.id </select> <insert id="addEmployee" parameterType="com.pbx.pojo.Employee"> insert into springboot.employee(last_name, email, gender, department, birth) values (#{name}, #{email}, #{gender}, #{department.id}, #{birth}) </insert> <update id="updateEmployee" parameterType="com.pbx.pojo.Employee"> update springboot.employee set last_name = #{name}, email=#{email}, gender=#{gender}, department=#{department.id} where id = #{id} </update> <delete id="deleteEmployee"> delete from springboot.employee where id = #{id} </delete> </mapper>
-
-
測試
@Test public void DepartmentTest() { DMapper.insertDepartment(new Department(106, "乾飯部門")); showDepartment(); DMapper.updateDepartment(new Department(106, "打工部")); showDepartment(); DMapper.deleteDepartment(106); showDepartment(); } public void showDepartment() { for (Department department : DMapper.getDepartmentList()) { System.out.println(department); } System.out.println("===================="); }
@Test public void EmployeeTest() { EMapper.addEmployee(new Employee(1, "布魯斯兒", "[email protected]", 1, DMapper.getDepartmentById(101), new Date())); showEmployee(); Map<String, Object> map = new HashMap<>(); map.put("id", 1); map.put("name", "裡卡呆"); EMapper.updateEmployee(map); showEmployee(); EMapper.deleteEmployee(1); showEmployee(); } public void showEmployee() { for (Employee employee : EMapper.getEmployeeList()) { System.out.println(employee); } System.out.println("============="); }
首頁
-
在配置類中給首頁新增幾個對映
@Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("index"); registry.addViewController("/index.html").setViewName("index"); registry.addViewController("/index").setViewName("index"); }
-
這樣的話,訪問上述任一路徑都可以到達我們的首頁,同時為了保證所有的靜態資源能被正確引用到,這裡我們要用
Thymeleaf
管理所有的靜態資源-
具體表現為用
Thymeleaf
來引用<!-- Bootstrap core CSS --> <link th:href="@{/css/bootstrap.min.css}" rel="stylesheet"> <!-- Custom styles for this template --> <link th:href="@{/css/signin.css}" rel="stylesheet">
-
i18n 國際化
-
在SpringBoot中配置國際化資源路徑
spring: messages: basename: i18n.message
-
建立中文的配置檔案和英文的配置檔案
-
zh_CN
alert=請登入 loginBtn=登入 password=密碼 remember=記住密碼(不建議在公共電腦上勾選) username=使用者名稱
-
en_US
alert=Please sign in loginBtn=SIGN IN password=Password remember=Remember Me (not recommended to set on public computers) username=username
-
-
在首頁中使用
-
實現中英文切換
-
給兩個連結新增地址
<a class="btn btn-sm" th:href="@{/zh/index}">中文</a> <a class="btn btn-sm" th:href="@{/en/index}">English</a>
-
配置Controller
@GetMapping("/{s}/index") public String changeLanguage(@PathVariable String s, HttpSession session) { // 為了保證語言資訊能跟著一起走,所有要放到session裡面 session.setAttribute("language", s); return "index"; }
-
重新配置Locale
public class LanguageConfig implements LocaleResolver { @Override public Locale resolveLocale(HttpServletRequest request) { String language = (String) request.getSession().getAttribute("language"); if ("zh".equals(language)) { return new Locale("zh", "CN"); } else if ("en".equals(language)) { return new Locale("en", "US"); } return request.getLocale(); } @Override public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) { } }
-
在MVC配置類中注入
@Bean public LocaleResolver localeResolver() { return new LanguageConfig(); }
-
-
效果展示
登入
-
修改index.html中的相應元素,使其能將登入表單提交到相應的位置
-
User實體類
@Data @AllArgsConstructor @NoArgsConstructor @Repository public class User { private int id; private String username; private String password; }
-
mapper介面和xml
@Mapper @Repository public interface UserMapper { User getUser(Map<String, String> map); }
<mapper namespace="com.pbx.mapper.UserMapper"> <select id="getUser" parameterType="map" resultType="com.pbx.pojo.User"> select * from springboot.user where username = #{username} and password = #{password} </select> </mapper>
-
登入服務
@Service public class LoginService { @Autowired private UserMapper mapper; public void setMapper(UserMapper mapper) { this.mapper = mapper; } public boolean login(Map<String, String> map) { return mapper.getUser(map) != null; } }
-
Controller設定
@Autowired private LoginService loginService; @PostMapping("/login") public String login(@RequestParam String username, @RequestParam String password) { Map<String, String> map = new HashMap<>(2); map.put("username", username); map.put("password", password); if (loginService.login(map)) { session.setAttribute("user", username); session.setAttribute("login", true); return "redirect:/dashboard"; } return "index"; }
-
測試
登入攔截器
-
現在我們的主頁可以在沒有登入的情況下直接訪問,那麼我們就需要使用攔截器去攔截所有的未登入情況下的所有請求,這也就是在登入的時候給session加了一個狀態的原因
-
自定義攔截器
public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object login = request.getSession().getAttribute("login"); if (login == null || login == Boolean.FALSE) { request.getRequestDispatcher("/index").forward(request, response); return false; } else { return true; } } }
-
註冊攔截器
@Override public void addInterceptors(InterceptorRegistry registry) { String[] exclude = {"/", "/index","/index.html","/login","/jss/**","/css/**","/js/**","/*/index"}; registry.addInterceptor(new LoginInterceptor()).excludePathPatterns(exclude); }
主頁
-
抽取公共元件,簡化模板檔案結構,提高程式碼複用,同時完成連結跳轉功能
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="topbar"> <a class="navbar-brand col-sm-3 col-md-2 mr-0" style="color:white;" th:text="${session.user}"></a> <ul class="navbar-nav px-3"> <li class="nav-item text-nowrap"> <a class="nav-link" th:href="@{/quit}" th:text="#{main.signout}"></a> </li> </ul> </nav> <nav class="col-md-2 d-none d-md-block bg-light sidebar" th:fragment="sidebar"> <div class="sidebar-sticky"> <ul class="nav flex-column"> <li class="nav-item"> <a th:class="${current=='main' ? 'nav-link active' : 'nav-link'}" th:href="@{/main}" th:text="#{main.main}"> </a> </li> <li class="nav-item"> <a th:class="${current=='employee' ? 'nav-link active' : 'nav-link'}" th:href="@{/employee}" th:text="#{main.employee}"> </a> </li> <li class="nav-item"> <a th:class="${current=='department' ? 'nav-link active' : 'nav-link'}" th:href="@{/department}" th:text="#{main.department}"> </a> </li> </ul> </div> </nav> </html>
-
主頁頁面
<body> <div th:replace="~{component/part::topbar}"></div> <div class="container-fluid"> <div class="row"> <div th:replace="~{component/part::sidebar}"></div> <main class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4" role="main"> <h1 th:text="'Hello ' + ${session.user}"></h1> </main> </div> </div> </body>
-
主頁Controller
@RequestMapping({"/dashboard", "/main"}) public String mainPage(Model model) { model.addAttribute("current", "main"); return "detail/main"; } @RequestMapping("/quit") public String quit(HttpSession session) { session.invalidate(); return "index"; }
-
效果展示
部門資訊展示
-
頁面
<body> <div th:replace="~{component/part::topbar}"></div> <div class="container-fluid"> <div class="row"> <div th:replace="~{component/part::sidebar}"></div> <main class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4" role="main"> <h1 th:text="#{main.department.title}">Department</h1> <div class="table-responsive"> <table class="table table-striped table-sm"> <thead> <tr> <th th:text="#{main.department.id}"></th> <th th:text="#{main.department.name}"></th> <th th:text="#{main.department.nums}"></th> </tr> </thead> <tbody> <tr th:each="k:${map}"> <td th:text="${k.getKey().getId()}"></td> <td th:text="${k.getKey().getName()}"></td> <td th:text="${map.get(k.getKey())}"></td> </tr> </tbody> </table> </div> </main> </div> </div> </body>
-
mapper
-
介面
@Mapper @Repository public interface DepartmentMapper { List<Department> getDepartmentList(); int countByDepartmentId(@Param("departmentID")int id); }
-
對映檔案
<mapper namespace="com.pbx.mapper.DepartmentMapper"> <select id="getDepartmentList" resultType="com.pbx.pojo.Department"> select * from springboot.department </select> <select id="countByDepartmentId" resultType="java.lang.Integer"> SELECT COUNT(id) num FROM springboot.employee WHERE department = #{departmentID} </select> </mapper>
-
-
Service
@Service public class DepartmentService { @Autowired private DepartmentMapper mapper; private List<Department> getDepartment() { return mapper.getDepartmentList(); } public Map<Department, Integer> countDepartment() { Map<Department, Integer> map = new LinkedHashMap<>(); List<Department> departmentList = getDepartment(); for (Department department : departmentList) { map.put(department, mapper.countByDepartmentId(department.getId())); } System.out.println(map); return map; } }
-
Controller
@GetMapping("/department") public String department(Model model) { model.addAttribute("current", "department"); Map<Department, Integer> map = departmentService.countDepartment(); model.addAttribute("map", map); return "detail/department"; }
-
效果
員工資訊展示
-
頁面
<body> <div th:replace="~{component/part::topbar}"></div> <div class="container-fluid"> <div class="row"> <div th:replace="~{component/part::sidebar}"></div> <main class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4" role="main"> <h2 th:text="#{main.employee.title}"></h2> <div class="table-responsive"> <table class="table table-striped table-sm"> <thead> <tr> <th th:text="#{main.employee.id}"></th> <th th:text="#{main.employee.name}"></th> <th th:text="#{main.employee.email}"></th> <th th:text="#{main.employee.gender}"></th> <th th:text="#{main.employee.department}"></th> <th th:text="#{main.employee.birth}"></th> <th th:text="#{main.employee.action}"></th> </tr> </thead> <tbody> <tr th:each="l:${list}"> <td th:text="${l.getId()}"></td> <td th:text="${l.getName()}"></td> <td th:text="${l.getEmail()}"></td> <td th:text="${l.getGender()==0 ? '女' : '男'}"></td> <td th:text="${l.getDepartment().getName()}"></td> <td th:text="${l.getBirth()}"></td> <td> <button class="btn btn-sm btn-primary" th:text="#{main.employee.edit}"></button> <button class="btn btn-sm btn-danger" th:text="#{main.employee.delete}"></button> </td> </tr> </tbody> </table> </div> </main> </div> </div> </body>
-
mapper
-
介面
@Mapper @Repository public interface EmployeeMapper { List<Employee> getEmployeeList(); Employee getOneById(@Param("employeeID") int id); int addEmployee(Employee employee); int updateEmployee(Map<String, Object> map); int deleteEmployee(int id); }
-
對映檔案
<mapper namespace="com.pbx.mapper.EmployeeMapper"> <!--因為實體類的欄位和資料庫的欄位不一致,所以要配置這resultMap和parameterMap--> <resultMap id="resultMap" type="com.pbx.pojo.Employee"> <!--有association之後就要配置所有屬性的對映--> <result property="id" column="id"/> <result property="name" column="last_name"/> <result property="email" column="email"/> <result property="gender" column="gender"/> <result property="birth" column="birth"/> <association property="department" javaType="com.pbx.pojo.Department"> <result property="id" column="did"/> <result property="name" column="dname"/> </association> </resultMap> <select id="getEmployeeList" resultMap="resultMap"> select e.id, e.last_name, e.email, e.gender, e.department, e.birth, d.id did, d.name dname from springboot.employee e, springboot.department d where e.department = d.id </select> <select id="getOneById" resultMap="resultMap"> select * from springboot.employee where id = #{employeeID} </select> <insert id="addEmployee" parameterType="com.pbx.pojo.Employee"> insert into springboot.employee(id, last_name, email, gender, department, birth) values (#{id}, #{name}, #{email}, #{gender}, #{department.id}, #{birth}) </insert> <update id="updateEmployee" parameterType="map"> update springboot.employee <set> <if test="name != null"> last_name = #{name} </if> <if test="email != null"> email = #{email} </if> <if test="gender != null"> gender = #{gender} </if> <if test="department != null"> department = #{department} </if> <if test="birth != null"> birth = #{birth} </if> </set> where id = #{id} </update> <delete id="deleteEmployee"> delete from springboot.employee where id = #{id} </delete> </mapper>
-
-
Service
@Service public class EmployeeService { @Autowired private EmployeeMapper mapper; public List<Employee> getEmployList() { return mapper.getEmployeeList(); } }
-
Controller
@GetMapping("/employee") public String employee(Model model) { model.addAttribute("current", "employee"); model.addAttribute("list", employeeService.getEmployList()); return "detail/employee"; }
-
展示
增、刪、改員工
增加
-
跳轉連結
<a th:href="@{/delete/}+${l.getId()}"><button class="btn btn-sm btn-danger" th:text="#{main.employee.delete}"></button></a>
-
頁面
<body> <div th:replace="~{component/part::topbar}"></div> <div class="container-fluid"> <div class="row"> <div th:replace="~{component/part::sidebar}"></div> <main class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4" role="main"> <form action="/add" method="post"> <div class="form-group"> <label for="name">姓名</label> <input type="text" class="form-control" id="name" placeholder="姓名" name="name"> </div> <div class="form-group"> <label for="email">郵箱</label> <input type="email" class="form-control" id="email" placeholder="郵箱" name="email"> </div> <div class="form-group"> <label>性別</label> <div class="form-check"> <input class="form-check-inline" type="radio" name="gender" value="0"> <label class="form-check-label">男</label> </div> <div class="form-check"> <input class="form-check-inline" type="radio" name="gender" value="1"> <label class="form-check-label">女</label> </div> </div> <div class="form-group"> <label for="department">部門</label> <select class="form-control" id="department" name="department.id"> <option th:each="dept:${list}" th:text="${dept.getName()}" th:value="${dept.getId()}"></option> </select> </div> <div class="form-group"> <label for="birth">出生日期</label> <input type="date" class="form-control" id="birth" placeholder="出生日期" name="birth"> </div> <button type="submit" class="btn btn-default">提交</button> </form> </main> </div> </div> </body>
-
Controller
@GetMapping("/add") public String toAdd(Model model) { model.addAttribute("list", departmentService.getDepartment()); return "detail/add"; } @PostMapping("/add") public String add(Employee employee) { System.out.println(employee); employeeService.addEmployee(employee); return "redirect:/employee"; }
-
展示
-
注意點:
-
日期格式的Formatter要記得設定
spring: mvc: format: date: yyyy-mm-dd
-
修改
-
跳轉連結
<a th:href="@{/edit/}+${l.getId()}"><button class="btn btn-sm btn-primary" th:text="#{main.employee.edit}"></button></a>
-
頁面
<body> <div th:replace="~{component/part::topbar}"></div> <div class="container-fluid"> <div class="row"> <div th:replace="~{component/part::sidebar}"></div> <main class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4" role="main"> <form th:action="@{/edit/}+${employee.getId()}" method="post"> <div class="form-group"> <label for="name">姓名</label> <input type="text" class="form-control" id="name" th:value="${employee.getName()}" th:name="${'name'}"> </div> <div class="form-group"> <label for="email">郵箱</label> <input type="email" class="form-control" id="email" th:value="${employee.getEmail()}" name="email"> </div> <div class="form-group"> <label>性別</label> <div class="form-check"> <input th:checked="${employee.getGender()==0}" class="form-check-inline" type="radio" name="gender" value="0"> <label class="form-check-label">男</label> </div> <div class="form-check"> <input th:checked="${employee.getGender()==1}" class="form-check-inline" type="radio" name="gender" value="1"> <label class="form-check-label">女</label> </div> </div> <div class="form-group"> <label for="department">部門</label> <select class="form-control" id="department" name="department.id"> <option th:selected="${dept.getId()==employee.getDepartment().getId()}" th:each="dept:${list}" th:text="${dept.getName()}" th:value="${dept.getId()}"></option> </select> </div> <div class="form-group"> <label for="birth">出生日期</label> <input type="date" class="form-control" id="birth" th:value="${#dates.format(employee.getBirth(),'yyyy-mm-dd')}" name="birth"> </div> <button type="submit" class="btn btn-default">提交</button> </form> </main> </div> </div> </body>
-
Controller
@GetMapping("/edit/{id}") public String toUpdate(@PathVariable int id, Model model) { Employee employee = employeeService.getOneByID(id); System.out.println(employee); model.addAttribute("employee", employee); model.addAttribute("list", departmentService.getDepartment()); return "detail/edit"; } @PostMapping("/edit/{id}") public String udate(@PathVariable int id, Employee employee) { System.out.println(id); System.out.println(employee); employeeService.updateEmployee(employee); return "redirect:/employee"; }
-
展示
刪除
-
跳轉連結
<a th:href="@{/delete/}+${l.getId()}"><button class="btn btn-sm btn-danger" th:text="#{main.employee.delete}"></button></a>
-
Controller
@GetMapping("/delete/{id}") public String delete(@PathVariable int id) { employeeService.deleteEmployee(id); return "redirect:/employee"; }
-
演示
![image-20201224220948227](https://gitee.com/primabrucexu/image/raw/main/image/20201224220948.png)
![image-20201224220954612](https://gitee.com/primabrucexu/image/raw/main/image/20201224220954.png)