Springboot-Management的項目實踐
準備工作
1.新建一個項目
next之後選擇SpringWeb
和Thymeleaf
,然後直接next,Finish即可。
之後我們進行測試,看是否搭建成功
ok,我們已經項目創建好瞭。
2.導入靜態資源
根據下方的圖片展示將資源導入
3.創建實體類
首先我們先導入lombok
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> </dependency>
創建pojo
的包,在其下創建兩個實體類Department和Employee
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; //部門表 @Data @AllArgsConstructor @NoArgsConstructor public class Department { private Integer id; private String departmentName; }
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; //員工表 @Data @AllArgsConstructor @NoArgsConstructor public class Employee { private Integer id; private String employeeName; private String email; private Integer gender; //0:女 1:男 private Department department; private Date birth; }
遇到的問題:有些人會遇到這個問題,為什麼我的lombok導入瞭,也用將其方法生成瞭,但是最後不能用,就像下面的情況
其實不要你以為寫瞭那三行就是有瞭,我們打開structure
看一下,發現雖然寫瞭,但是還是沒有方法。這又是為什麼呢?
其實是因為你的IDEA裡面沒有Lombok的插件,隻需要在Setting->Plugins->搜索lombok->Install->重新啟動idea
最後看下成果
4.編寫dao層
同樣建包dao
,並在其下創建DepartmentDao
和EmployeeDao
import com.hxl.pojo.Department; import org.springframework.stereotype.Repository; import java.util.Collection; import java.util.HashMap; import java.util.Map; //部門dao //註冊到IOC容器中 @Repository public class DepartmentDao { //模擬數據庫中的數據 private static Map<Integer, Department> departments = null; static { departments = new HashMap<Integer, Department>(); departments.put(1, new Department(1, "教學部")); departments.put(2, new Department(2, "市場部")); departments.put(3, new Department(3, "調研部")); departments.put(4, new Department(4, "後勤部")); departments.put(5, new Department(5, "運營部")); } //獲得所有部門信息 public Collection<Department> getDepartments(){ return departments.values(); } //通過id得到部門 public Department getDepartmentById(Integer id){ return departments.get(id); } }
import com.hxl.pojo.Department; import com.hxl.pojo.Employee; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Map; //員工dao //註冊到IOC容器中 @Repository public class EmployeeDao { //模擬數據庫中的數據 static private Map<Integer, Employee> employees = null; //員工所屬的部門 @Autowired private DepartmentDao departmentDao; static { employees = new HashMap<Integer, Employee>();//創建一個員工表 employees.put(1, new Employee(1, "hxl", "[email protected]", 1, new Department(1, "教學部"), new Date())); employees.put(2, new Employee(2, "zmc", "[email protected]", 1, new Department(2, "市場部"), new Date())); employees.put(3, new Employee(3, "kwb", "[email protected]", 0, new Department(3, "調研部"), new Date())); employees.put(4, new Employee(4, "lqs", "[email protected]", 1, new Department(4, "後勤部"), new Date())); employees.put(5, new Employee(5, "wjr", "[email protected]", 1, new Department(5, "運營部"), new Date())); } //主鍵自增 private static Integer initialId = 6; //增加一個員工 public void addEmployee(Employee employee) { if (employee.getId() == null) { employee.setId(initialId++); } employee.setDepartment(departmentDao.getDepartmentById(employee.getDepartment().getId())); employees.put(employee.getId(), employee); } //查詢全部員工信息 public Collection<Employee> getAllEmployees() { return employees.values(); } //通過id查詢員工 public Employee getEmployeeById(Integer id) { return employees.get(id); } //通過id刪除員工 public void deleteEmployeeById(int id) { employees.remove(id); } }
至此我們的準備工作就完成瞭。
首頁實現
首先我們像之前創建一個config
的包用來存放自定義的配置
創建一個MyMvcConfig
的配置類,進行首頁的視圖跳轉
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class MyMvcConfig implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { //添加一個,打瞭"/",然後讓他去index registry.addViewController("/").setViewName("index"); registry.addViewController("index.html").setViewName("index"); } }
啟動程序,進行測試訪問localhost:8080/
或者locahost:8080/index.html
出現下面的界面就ok瞭
在這塊中,我們發現僅有一些文字,樣式圖片等都沒有加載出來,這是因為我們之前導入的靜態資源的html
,沒有使用Thymeleaf
的的語法。我們的模板引擎為Thymeleaf
。
我們將之前導入的html
裡面的都改為thymeleaf
語法。
註意所有html都需要引入Thymeleaf命名空間
<xmlns:th="http://www.thymeleaf.org">
然後修改所有頁面靜態資源的引入,使用@{...}
鏈接表達式(隻要是自己本地的鏈接資源,都需要根據這個語法來修改)
在標簽前增加th:
以index.html
為例
註意:第一個/代表項目的classpath,也就是這裡的resources目錄
修改之後我們再次運行
中英文切換
首先我們要保證我們的編碼是UTF-8
Properties編寫
接下來我們進行配置編寫,在resources
目錄下創建一個文件夾i18n
,然後在其下創建一個login.properties
和login_zh_CN.properties
創建完成後發現他們兩個合並瞭。
這樣我們就有瞭默認配置和中文的配置,接下來再創建一個英語的,來看步驟:
這樣我們就有瞭三個文件。展示操作的時候到瞭
首先點擊這裡,可以讓我們擁有可視化操作。沒有可視化選項的兄弟下載插件Flagiarism然後重啟就可以瞭
接下來將我們的內容一次創建
直接點擊+
號,創建文件名和輸入內容即可。
之後我們就會發現這裡也會增加內容。
接下來按照圖片一次進行創建
這裡展示一個內容
login.properties
login.btn=登錄 login.password=密碼 login.remember=記住我 login.tip=請登錄 login.username=用戶名
login_en_US.properties
login.btn=Sign in login.password=Password login.remember=Remember me login.tip=Please sign in login.username=Username
我們設置完之後,該怎麼讓我們的項目識別呢。需要在我們的application.properties
下進行綁定
# 我們的配置文件的真實位置 spring.messages.basename=i18n.login
源碼分析:
我們去MessageSourceAutoConfiguration
這個類下,查看messageSource
該方法
public MessageSource messageSource(MessageSourceProperties properties);
可以看到,他的參數是一個MessageSourceProperties
對象,我們繼續查看,它首先是一個屬性basename
,默認值為message
- 如果你不在springboot配置文件中指定以
.
分隔開的國際化資源文件名稱的話 - 它默認會去類路徑下找messages.properties作為國際化資源文件
這也就是我們為什麼要在配置文件中進行配置。
後面好瞭,那麼我們的html頁面該怎麼進行呢。查閱資料發現Thymeleaf
中取值需要進行使用到#{}
例如
<th:text="#{login.tip}">
根據上述步驟將其他的幾處也進行修改
最後的效果
接下來就是可以中英文進行切換,此時需要加一個組件
在我們的首頁界面中可以看到我們的兩個中英文標簽
<a class="btn btn-sm">中文</a> <a class="btn btn-sm">English</a>
此時我們需要對其加上跳轉鏈接同時加上參數,原來我們的參數是?
現在不需要,用的是()
。
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}" rel="external nofollow" >中文</a> <a class="btn btn-sm" th:href="@{/index.html(l='en_US')}" rel="external nofollow" >English</a>
自定義地區的解析器組件
在spring中,有兩個關於國際化的類,一個是代表地區的Locale
,每一個對象都代表瞭特定的區域,還有一個關於地區解析器LocaleResolver
。
首先搜索WebMvcAutoConfiguration
,可以在其中找到關於一個方法localeResolver()
@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
地區對象解析器:
- 如果用戶配置瞭則使用用戶配置的地區解析器;
- 如果用戶沒有配置,則使用默認的地區解析器
可以發現它繼承瞭LocaleResolver
接口,實現瞭地區解析
因此我們想要實現上述自定義的國際化資源生效,隻需要編寫一個自己的地區解析器,繼承LocaleResolver
接口,重寫其方法即可
在config包下新建一個MyLocaleResolver
package com.hxl.config; 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 MyLocaleResolver implements LocaleResolver { @Override public Locale resolveLocale(HttpServletRequest httpServletRequest) { //獲取請求中的國際化參數 String language = httpServletRequest.getParameter("l"); //默認的地區 Locale locale = Locale.getDefault(); //如果請求的鏈接參數不為空,攜帶瞭國際化參數 if (!StringUtils.isEmpty(language)) { String[] split = language.split("_");//zh_CN(語言_地區) locale = new Locale(split[0], split[1]); } return locale; } @Override public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) { } }
完成組件後,需要在MvcConfig
配置類下添加上我們的Bean
//自定義的國際化組件生效 @Bean public LocaleResolver localeResolver() { return new MyLocaleResolver(); }
重新啟動項目,我們就可以通過點擊下方的中英文來進行切換。
總結
- 我們需要配置
i18n
文件 - 需要自定義一個組件
MyLocaleResolver
,以便在項目中進行按鈕的自動切換。 - 將自己的組件配置到spring容器中
@Bean
- 取值用的是
#{}
登錄功能
1.頁面調整
我們需要將這裡進行修改。
查看頁面之後發現,我們點擊登錄
按鈕的時候會進入dashboard
頁面。
所以我們需要將這裡的提交地址進行修改,以及將用戶名和密碼框加上屬性以便傳參。
2.編寫LoginController
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller public class LoginController { @RequestMapping("/user/login") public String login(@RequestParam("username") String username,@RequestParam("password") String password, Model model){ //如果用戶名和密碼都正確 if("wangmm".equals(username) && "123456".equals(password)){ return "dashboard"; }else{ //如果用戶名或者密碼不正確 model.addAttribute("msg","用戶名或者密碼不正確"); return "index"; } } }
我們需要在登錄頁面增加一個返回錯誤信息的標簽。
此時啟動程序並訪問localhost:8080
。輸入正確的賬號密碼訪問我們可以看到這個頁面
輸入錯誤的賬號密碼會呈現
好瞭,我們這裡已經成功瞭。但是當我們成功登錄後我們的頁面顯示不全,這是因為之前提到的靜態頁面展示的問題,需要把我們dashboard
頁面下的本地靜態資源都用Thymeleaf
語法進行修改。修改成功後即可。
同時我們可以到瀏覽器頁面的url
暴露瞭我們的信息。所以我們需要進行修改。
在自定義的配置類MyMvcConfig
中增加。這樣我們訪問main.html
也就是訪問瞭dashboard
頁面。
registry.addViewController("/main.html").setViewName("dashboard");
同時我們也要去將LoginController
下的登錄頁面也重定向到main.html
中。
@Controller public class LoginController { @RequestMapping("/user/login") public String login(@RequestParam("username") String username,@RequestParam("password") String password, Model model){ //如果用戶名和密碼都正確 if("wangmm".equals(username) && "123456".equals(password)){ return "redirect:/main.html"; }else{ //如果用戶名或者密碼不正確 model.addAttribute("msg","用戶名或者密碼不正確"); return "index"; } } }
之後我們運行查看,瀏覽器上的url
不再攜帶用戶的信息。
此時出現瞭新的問題,就是我們不管登錄不登錄,通過localhost:8080/main.html
都可以訪問到我們的dashboard
的頁面。
3.登錄攔截器
在config
目錄下,新建一個登錄攔截器類LoginHandlerInterceptor
目的:用戶登錄成功後得到用戶的信息。防止未登錄用戶查看頁面
得到用戶信息,我們需要先保存用戶的信息,所以我們需要在LoginController
中當用戶登錄成功後,存入用戶信息到session
中
@Controller public class LoginController { @RequestMapping("/user/login") public String login(@RequestParam("username") String username,@RequestParam("password") String password, Model model, HttpSession session){ //如果用戶名和密碼都正確 if("wangmm".equals(username) && "123456".equals(password)){ session.setAttribute("LoginUser", username); return "redirect:/main.html"; }else{ //如果用戶名或者密碼不正確 model.addAttribute("msg","用戶名或者密碼不正確"); return "index"; } } }
實現攔截器。需要繼承HandlerInterceptor
接口
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; 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 { //用戶登錄成功擁有session Object loginUser = request.getSession().getAttribute("LoginUser"); if(loginUser == null){ request.setAttribute("msg","用戶權限不夠,請登錄"); //權限不夠就重定向到首頁 request.getRequestDispatcher("/index.html").forward(request,response); return false; }else{ return true; } } }
有瞭攔截器就需要註冊到bean
中,在MyMvcConfig
配置類中,添加我們自定義的攔截器,註意屏蔽主頁、登錄相關請求、靜態資源的攔截
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginHandlerInterceptor()) .addPathPatterns("/**") .excludePathPatterns("/index.html", "/", "/user/login", "/asserts/**"); }
註意這個地方,有些人不是在整一個文件夾中,所以需要分開寫"/css/**", "/js/**", "/img/**"
測試:啟動程序直接訪問http://localhost:8080/main.html
之後我們登錄,成功之後再重新進入之前的鏈接http://localhost:8080/main.html
發現也是可以訪問得到的。
這是因為登錄之後用戶的信息已經保存在瞭session
中。攔截器自然不會攔截。
員工信息——查
實現界面中的Customers
中的員工查詢。
th:fragment="sidebar"
th:replace="~{commons/commons::topbar}"
- 如果要傳遞參數,可以直接使用
()
傳參,接收判斷即可 - 列表循環展示
首先我們先將模板中的跳轉鏈接進行跳轉
同時將list.html
中的代碼進行修改
在templates
目錄下新建一個包emp
用來存放員工的相關頁面
之後我們編寫對應的Controller
package com.hxl.controller; import com.hxl.dao.EmployeeDao; import com.hxl.pojo.Employee; 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 java.util.Collection; @Controller public class EmployeeController { @Autowired private EmployeeDao employeeDao; @RequestMapping("/emps") public String list(Model model){ Collection<Employee> employees = employeeDao.getAllEmployees(); model.addAttribute("emps",employees); return "emp/list"; } }
啟動測試,發現是這個頁面,這是由於咱們的語法有問題,和之前的一樣將本地靜態資源進行修改。
之後進行修改可以得到新的界面。
優化
點擊員工管理之後應該是高亮的狀態,但是我們發現點擊之後高亮不在Customers
而在Dashboard
同時我們可以將側邊欄以及頂部欄公共的部分進行提煉
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <!--頂部導航欄,利用th:fragment提取出來,命名為topbar--> <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" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >Company name</a> <input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search"> <ul class="navbar-nav px-3"> <li class="nav-item text-nowrap"> <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >Sign out</a> </li> </ul> </nav> <!--側邊欄,利用th:fragment提取出來,命名為sidebar--> <nav class="col-md-2 d-none d-md-block bg-light sidebar" th:fragment="siderbar"> <div class="sidebar-sticky"> <ul class="nav flex-column"> <li class="nav-item"> <a class="nav-link active" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" > <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-home"> <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path> <polyline points="9 22 9 12 15 12 15 22"></polyline> </svg> Dashboard <span class="sr-only">(current)</span> </a> </li> <li class="nav-item"> <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" > <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-file"> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path> <polyline points="13 2 13 9 20 9"></polyline> </svg> Orders </a> </li> <li class="nav-item"> <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" > <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-shopping-cart"> <circle cx="9" cy="21" r="1"></circle> <circle cx="20" cy="21" r="1"></circle> <path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path> </svg> Products </a> </li> <li class="nav-item"> <a class="nav-link" th:href="@{/emps}" rel="external nofollow" > <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> Customers </a> </li> <li class="nav-item"> <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" > <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-bar-chart-2"> <line x1="18" y1="20" x2="18" y2="10"></line> <line x1="12" y1="20" x2="12" y2="4"></line> <line x1="6" y1="20" x2="6" y2="14"></line> </svg> Reports </a> </li> <li class="nav-item"> <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" > <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-layers"> <polygon points="12 2 2 7 12 12 22 7 12 2"></polygon> <polyline points="2 17 12 22 22 17"></polyline> <polyline points="2 12 12 17 22 12"></polyline> </svg> Integrations </a> </li> </ul> <h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted"> <span>Saved reports</span> <a class="d-flex align-items-center text-muted" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" > <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-plus-circle"> <circle cx="12" cy="12" r="10"></circle> <line x1="12" y1="8" x2="12" y2="16"></line> <line x1="8" y1="12" x2="16" y2="12"></line> </svg> </a> </h6> <ul class="nav flex-column mb-2"> <li class="nav-item"> <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" > <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-file-text"> <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path> <polyline points="14 2 14 8 20 8"></polyline> <line x1="16" y1="13" x2="8" y2="13"></line> <line x1="16" y1="17" x2="8" y2="17"></line> <polyline points="10 9 9 9 8 9"></polyline> </svg> Current month </a> </li> <li class="nav-item"> <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" > <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-file-text"> <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path> <polyline points="14 2 14 8 20 8"></polyline> <line x1="16" y1="13" x2="8" y2="13"></line> <line x1="16" y1="17" x2="8" y2="17"></line> <polyline points="10 9 9 9 8 9"></polyline> </svg> Last quarter </a> </li> <li class="nav-item"> <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" > <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-file-text"> <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path> <polyline points="14 2 14 8 20 8"></polyline> <line x1="16" y1="13" x2="8" y2="13"></line> <line x1="16" y1="17" x2="8" y2="17"></line> <polyline points="10 9 9 9 8 9"></polyline> </svg> Social engagement </a> </li> <li class="nav-item"> <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" > <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-file-text"> <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path> <polyline points="14 2 14 8 20 8"></polyline> <line x1="16" y1="13" x2="8" y2="13"></line> <line x1="16" y1="17" x2="8" y2="17"></line> <polyline points="10 9 9 9 8 9"></polyline> </svg> Year-end sale </a> </li> </ul> </div> </nav> </html>
提取頁面的公共部分
我們可以將兩個頁面dashboard.html和
list.html`中頂部導航欄和側邊欄的代碼刪除
啟動測試查看:所有頂部和側邊都沒有瞭
將公共的部分引入
在dashboard.html
和list.html
刪除的部分插入提取出來的公共部分topbar
和sidebar
<!--頂部導航欄--> <div th:replace="~{commons/commons::topbar}" }></div> <!--側邊欄--> <div th:replace="~{commons/commons::siderbar}"></div>
解決高亮
通過觀察,在頁面中高亮的部分是由於class="nav-link active"
屬性
我們可以通過傳遞參數來進行判斷說明自己的頁面應該哪裡高亮
將dashboard.html
的側邊欄標簽傳遞參數active
為dashboard.html
<!--側邊欄--> <div th:replace="~{commons/commons::siderbar(active='dashboard.html')}"></div>
將list.html
的側邊欄標簽傳遞參數active
為list.html
<!--頂部導航欄--> <div th:replace="~{commons/commons::siderbar(active='list.html')}" }></div>
我們將頁面參數修改後需要在公共頁面部分接收參數active
th:class="${active=='dashboard.html'?'nav-link active':'nav-link'}" th:class="${active=='list.html'?'nav-link active':'nav-link'}"
測試:
點擊Customers
,Customers
高亮,成功
顯示員工信息
將list.html
中數據進行修改,顯示員工的信息,並添加編輯和刪除的標簽
<table class="table table-striped table-sm"> <thead> <tr> <th>id</th> <th>employeeName</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.getId()}"></td> <td th:text="${emp.getEmployeeName()}"></td> <td th:text="${emp.getEmail()}"></td> <td th:text="${emp.getGender()==0?'女':'男'}"></td> <td th:text="${emp.getDepartment().getDepartmentName()}"></td> <td th:text="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm:ss')}"></td> <td> <a class="btn btn-sm btn-primary">編輯</a> <a class="btn btn-sm btn-danger">刪除</a> </td> </tr> </tbody> </table>
修改成功後,測試
員工信息——增
- 按鈕提交
- 跳轉到添加頁面
- 添加員工成功
- 返回首頁
表單提交盡量用重定向:redirect
,否則容易出現表單重復提交
首先增加提交按鈕
在list.html
中增加一個添加員工
的按鈕,點擊按鈕時發起有一個/addEmps
的請求
<a class="btn btn-sm btn-success" th:href="@{/addEmps}" rel="external nofollow" >添加員工</a>
這裡去編寫對應的controller
,處理請求。
通過get
的方式進行請求提交,所以在EmployeeController
中添加一個方法addEmps
用來處理list
頁面點擊提交按鈕的操作,返回到add.html
添加員工頁面(頁面需要增加,原先沒有)
註意在最開始的地方將departmentDao
進行裝配
@Autowired private DepartmentDao departmentDao;
@GetMapping("/addEmps") public String add(Model model) { //查出所有的部門信息,添加到departments中,用於前端接收 Collection<Department> departments = departmentDao.getDepartments(); model.addAttribute("departments", departments); return "emp/add";//返回到添加員工頁面 }
創建員工界面add.html
在我們的templates/emp
下新建一個add.html
,隻需要將list.html
界面進行復制,然後修改表單即可。修改內容如下:
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4"> <form> <div class="form-group"> <label>EmployeeName</label> <input type="text" name="employeeName" class="form-control" placeholder="employeeName:hxl"> </div> <div class="form-group"> <label>Email</label> <input type="email" name="email" class="form-control" placeholder="email:[email protected]"> </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> <!--註意這裡的name是department.id,因為傳入的參數為id--> <!--我們在controller中接收的是一個Employee,所以我們需要提交的是其中的一個屬性--> <select class="form-control" name="department.id"> <option th:each="department:${departments}" th:text="${department.getDepartmentName()}" th:value="${department.getId()}"></option> </select> </div> <div class="form-group"> <label>Birth</label> <!--springboot默認的日期格式為yy/MM/dd--> <input type="text" name="date" class="form-control" placeholder="birth:yyyy/MM/dd"> </div> <button type="submit" class="btn btn-primary">添加</button> </form> </main>
註意下拉框中的內容應該是我們自己部門名。通過遍歷得到
<!--通過遍歷得到部門的信息,顯示是部門的名字,傳入的是部門的id--> <option th:each="department:${departments}" th:text="${department.getDepartmentName()}" th:value="${department.getId()}"></option>
測試:
員工請求addEmps
在add.html
頁面,當我們填寫完信息,點擊添加
按鈕,應該完成添加返回到list
頁面,展示新的員工信息;因此在add.html
點擊添加
按鈕的一瞬間,我們同樣發起一個請求/addEmps
,與上述提交按鈕
發出的請求路徑一樣,但這裡發出的是post
請求
編寫對應的controller
@PostMapping("/addEmps") public String addEmp(Employee employee) { employeeDao.addEmployee(employee);//添加一個員工 return "redirect:/emps";//重定向到/emps,刷新列表,返回到list頁面 }
測試:
提交之後我們可以跳轉到員工頁面查看我們的新增加的員工
差一個添加成功的圖片
同時這裡需要註意:日期格式必須是yyyy/MM/dd
才能正確跳轉,否則就會出錯。因為這是spring默認的,如果要修改日期格式,需要在application.properties
中進行修改
spring.mvc.date-format=yyyy-MM-dd
這樣日期格式就變瞭,此時原來的格式就不能用瞭
鏈接形式處理是getMapping
員工信息——改
首頁編輯按鈕
當我們點擊編輯
時,應該跳轉到更新員工的頁面update.html
,在list.html
中修改
<a class="btn btn-sm btn-primary" th:href="@{/update/{id}(id=${emp.getId()})}" rel="external nofollow" >編輯</a>
這裡進行跳轉就需要GetMapping
編寫對應controller,在EmployeeController
中添加一個方法update
用來處理list
頁面點擊編輯
按鈕的操作,返回到update.html
//restful風格接收參數 @GetMapping("/update/{id}") public String update(@PathVariable("id") int id, Model model) { //查詢指定id的員工,添加到empByID中,用於前端接收 Employee employeeByID = employeeDao.getEmployeeById(id); model.addAttribute("empByID", employeeByID); //查出所有的部門信息,添加到departments中,用於前端接收 Collection<Department> departments = departmentDao.getDepartments(); model.addAttribute("departments", departments); return "emp/update";//返回到編輯員工頁面 }
更新員工的頁面
復制add.html
並修改
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4"> <form th:action="@{/update}" method="post"> <input type="hidden" name="id" th:value="${empByID.getId()}"> <div class="form-group"> <label>employeeName</label> <input th:value="${empByID.getEmployeeName()}" type="text" name="employeeName" class="form-control" placeholder="employeeName:hxl"> </div> <div class="form-group"> <label>Email</label> <input th:value="${empByID.getEmail()}" type="email" name="email" class="form-control" placeholder="email:[email protected]"> </div> <div class="form-group"> <label>Gender</label><br/> <div class="form-check form-check-inline"> <input th:checked="${empByID.getGender()==1}" 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 th:checked="${empByID.getGender()==0}" 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> <!--註意這裡的name是department.id,因為傳入的參數為id--> <select class="form-control" name="department.id"> <option th:selected="${department.getId()==empByID.department.getId()}" th:each="department:${departments}" th:text="${department.getDepartmentName()}" th:value="${department.getId()}"> </option> </select> </div> <div class="form-group"> <label>Birth</label> <!--springboot默認的日期格式為yyyy/MM/dd--> <input th:value="${#dates.format(empByID.getBirth(),'yyyy/MM/dd')}" type="text" name="date" class="form-control" placeholder="birth:yyyy/MM/dd"> </div> <button type="submit" class="btn btn-primary">修改</button> </form> </main>
這裡已經將日期格式進行瞭修改,沒有修改之前的日期是不太正確的。
同時頁面跳轉的時候需要將Id攜帶過去。但是不能顯示出來,所以需要hidden
在上方已經有標註。
頁面提交請求
頁面編輯完成後會發起一個請求
<form th:action="@{/update}" method="post">
這需要我們去controller中處理請求
@PostMapping("/update") public String updateEmp(Employee employee) { employeeDao.addEmployee(employee);//添加一個員工 return "redirect:/emps";//添加完成重定向到/emps,刷新列表 }
測試:
原來的信息:
點擊編輯之後:
修改之後:
?
成功將員工進行瞭修改。
員工信息——刪
點擊刪除進行請求跳轉:修改我們的刪除標簽
<a class="btn btn-sm btn-success" th:href="@{/delete/{id}(id=${emp.getId()})}" rel="external nofollow" >刪除</a>
然後編寫對應的controller,處理點擊刪除
按鈕的請求,刪除指定員工,重定向到/emps
請求,更新員工信息
@GetMapping("/delete/{id}") public String delete(@PathVariable("id") Integer id) { employeeDao.deleteEmployeeById(id); return "redirect:/emps"; }
測試:
刪除成功
錯誤頁面定制
404頁面定制
springboot中錯誤頁面定制比較簡單,比如說404。直接在thmplates
下新建一個error
文件夾,然後將404頁面直接丟進去即可。
登錄測試一下
註銷
在我們提取出來的公共commons
頁面,頂部導航欄處中的標簽添加href
屬性,實現點擊發起請求/user/logout
<a class="nav-link" th:href="@{/user/logout}" rel="external nofollow" >Sign out</a>
去LoginController
中編寫對應的方法,清除session,並重定向到首頁
@RequestMapping("/user/logout") public String logout(HttpSession session) { session.invalidate(); return "redirect:/index.html"; }
測試:點擊右上角的Sign out
就可以退出界面,訪問main.html
是沒有權限的。
到此這篇關於Springboot-Management的項目實踐的文章就介紹到這瞭,更多相關Springboot Management內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- python 如何獲取頁面所有a標簽下href的值
- python 實現添加標簽&打標簽的操作
- SpringMVC RESTFul實戰案例刪除功能實現
- thymeleaf實現前後端數據交換的示例詳解
- 基於javascript實現移動端輪播圖效果