SpringBoot7_Web實戰3

總目標:開發一個spingboot的web項目,項目地址:點我
今天的主要任務是完成員工列表的增刪改功能。

1. 增加

  1. 在list頁面,對增加按鈕添加映射路徑

    <a class="btn btn-sm btn-success" th:href="@{/emp}">員工添加</a>
    
  2. 在templates/emp文件夾下添加add.html

    add頁面與list頁面相比,topbar和sidebar不變,只不過主體內容多了一個form表單

    <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="[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>
            <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>
    
  3. EmployeeController添加映射

    @Autowired
    DepartmentDao departmentDao;
    
    //來到員工添加頁面
    @GetMapping("/emp")
    public String toAddPage(Model model){
        Collection<Department> departments = departmentDao.getDepartments();
        model.addAttribute("depts", departments);
        return "emp/add";
    }
    
  4. 添加頁面填寫的部門信息,是根據請求域中的depts來填充的,修改add.html

    <div class="form‐group">
        <label>department</label>
        <select class="form‐control">
            <option th:id="${dept.id}" th:each="dept:${depts}" th:text="${dept.departmentName}">1</option>
        </select>
    </div>
    
  5. 在添加頁面,修改form表單映射路徑,根據web實戰1中的框架設計,添加員工的請求路徑爲/emp,請求方式爲post

    <form th:action="@{/emp}" method="post">
    

    還要注意form表單中提交的每一個數據都要加上name屬性,屬性值要和實體類Employee對應
    在這裏插入圖片描述

  6. 在EmployeeeController處理請求

    //員工添加
    //springmvc自動關機將請求參數與入參對象的屬性進行一一綁定,
    //前提是請求參數的名字與javaBean的屬性值要一致。
    @PostMapping("/emp")
    public String addEmp(Employee employee){
    
        System.out.println("保存的員工信息"+employee);
        employeeDao.save(employee);
        //如果返回員工列表用return "emps",將自動拼接爲classpath:/templates/emps.html
        return "redirect:/emps";
    }
    
  7. 日期提交格式默認是按照yyyy/MM/dd,其他格式就會出現400錯誤。如果想使用yyyy-MM-dd的格式,需要在application.properties文件中添加

    spring.mvc.date-format=yyyy-MM-dd
    

    這時就能用yyyy-MM-dd而不能使用yyyy/MM/dd的格式。

2. 修改

  1. 根據本實驗的請求架構

    實驗功能 請求URI 請求方式
    來到修改頁面 emp/{id} GET
    修改員工 emp PUT

    點擊list頁面中的編輯按鈕,會發送emp/{id}請求,在list.html中使用連接字符串的方式構成請求路徑。

    我直接在add.html中做修改,使add.html同時能夠完成添加員工和修改員工的功能。

    <a class="btn btn-sm btn-primary" th:href="@{/emp/}+${emp.id}">編輯</a>
    
  2. 在EmployeeController中處理請求

//來到修改頁面,查出當前員工以及部門信息,在頁面回顯
@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);

    //回到修改頁面(使add.html同時完成添加和修改員工的功能)
    return "emp/add";
}
  1. 修改add.html,爲每個input標籤添加value值,當點擊編輯按鈕的時候,能夠回顯當前員工的值
    在這裏插入圖片描述

  2. 但是經過上一步的修改,add.html頁面的添加功能被擾亂了。修改的時候請求域中有employee和departmeng對象,而添加的時候請求域中只有department對象。當點擊添加按鈕,employee爲空,所以添加頁面很多元素都不顯示。我們可以根據emp是否爲空來判斷當前add.html是在處理修改還是在添加員工
    在這裏插入圖片描述
    當點擊編輯按鈕,進入編輯頁面,頁面底部的按鈕要根據當前add.html正在完成的功能顯示爲修改添加

    <button type="submit" class="btn btn-primary" th:text="${emp!=null}?'修改':'添加'"></button>
    
  3. 接下來,點擊修改頁面底部的修改按鈕要發送put請求,但是不能直接將表單的請求方法直接改爲put

    在springmvc中有三步:

    1)SpringMVC中配置HiddenHttpMethodFilter,其將請求轉換爲指定的方式 (在springboot已自動配置好)

    2)頁面創建一個post表單(當前form即爲post請求)

    3)創建一個input項,name="_method";value的屬性值就是我們指定的請求方式

    在springboot只需要進行後兩步,我們添加一個隱藏的input標籤,指定value的值爲put,並且當emp不爲空(即當前處理的是修改請求)

    <form th:action="@{/emp}" method="post">
    	<input type="hidden" name="_method" value="put" th:if="${emp!=null}"/>
    
  4. 點擊修改按鈕後,上一步已將請求方式改爲put,接下來需要在EmployeeController中添加處理該請求的方法。

        @PutMapping("/emp")
        public String updateEmployee(Employee employee){
            System.out.println("修改的員工的數據"+employee);
            employeeDao.save(employee);
            return "redirect:/emps";
        }
    

    運行程序,修改一個員工信息爲例,發現控制檯輸出的員工信息缺少id,且員工信息沒有修改,而是多加了一個員工,將剛纔的修改信息添加到一個新員工中去了
    在這裏插入圖片描述
    是因爲調用EmployeeDao中的save()方法時,如果沒有員工id,會自增長id,並添加新員工

    private static Integer initId = 1006;
    
    public void save(Employee employee){
        if(employee.getId() == null){
            employee.setId(initId++);
        }
    
        employee.setDepartment(departmentDao.getDepartment(employee.getDepartment().getId()));
        employees.put(employee.getId(), employee);
    }
    

    因此,當我們修改員工信息時,需要在add.html中提交一個員工id,我們用隱藏的input標籤來完成

    <input type="hidden" name="id" th:if="${emp!=null}" th:value="${emp.id}"/>
    

    至此,修改的功能就完成了。
    如果不能提交put請求,請查看第4部分的bug處理

3. 刪除

  1. 根據本實驗的請求架構

    實驗功能 請求URI 請求方式
    刪除員工 emp/{id} DELETE

    點擊list頁面中的刪除按鈕,會發送emp/{id}的delete方式的請求,在list.html中使用連接字符串的方式構成請求路徑。我們使用隱藏的input標籤來指定delete請求

    <form th:action="@{/emp/}+${emp.id}" method="post">
        <input type="hidden" name="_method" value="delete"/>
        <button type="submit" class="btn btn-sm btn-danger">刪除</button>
    </form>
    
  2. 在EmployeeController處理請求

    //刪除員工
    @DeleteMapping("/emp/{id}")
    public String deleteEmployee(@PathVariable("id") Integer id){
        System.out.println("id:"+id);
        employeeDao.delete(id);
        return "redirect:/emps";
    }
    

    運行程序,能夠實現刪除員工的功能,但是list頁面中的每一個刪除按鈕都關聯着一個form表單,顯得比較笨重,於是下一步打算把form表單抽取出來,使用js的方式來發送請求。

  3. 使用js提交請求,這個請求地址應該是從刪除按鈕獲取的。我們給刪除按鈕添加一個自定義的屬性,裏面放入請求路徑,在js中,將這個自定義屬性的值作爲表單form的action值。

    刪除按鈕相關代碼爲

    <button th:attr="del_uri=@{/emp/}+${emp.id}" class="btn btn-sm btn-danger deleteBtn">刪除</button>
    

    將表單放到其他地方

    <form id="deleteEmpForm"  method="post">
        <input type="hidden" name="_method" value="delete"/>
    </form>
    

在這裏插入圖片描述
在list.html中添加js代碼

<script>
    $(".deleteBtn").click(function(){
    //刪除當前員工的
    $("#deleteEmpForm").attr("action",$(this).attr("del_uri")).submit();
    return false;
});
</script>

然後就大功告成了。

4. bug處理

springboot自動配置了hiddenHttpMethodFilter,這個過濾器幫我們把post請求轉換爲put請求或delete請求。但是我自己動手實踐的過程中,發現這個自動配置並沒有生效。

解決方式有兩種:

  1. 自己在配置類中添加一個過濾器

    //hiddenHttpMethodFilter
    @Bean
    public FilterRegistrationBean timeFilter() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        HiddenHttpMethodFilter myFilter = new HiddenHttpMethodFilter();
        registrationBean.setFilter(myFilter);
        ArrayList<String> urls = new ArrayList<>();
        urls.add("/*");//配置過濾規則
        registrationBean.setUrlPatterns(urls);
        return registrationBean;
    }
    
  2. 在application.properties中修改默認配置
    查看WebMvcAutoConfig,發現其關於HiddenHttpMethodFilter的代碼如下所示:

    @Bean
    @ConditionalOnMissingBean({HiddenHttpMethodFilter.class})
    @ConditionalOnProperty(
        prefix = "spring.mvc.hiddenmethod.filter",
        name = {"enabled"},
        matchIfMissing = false
    )
    public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
        return new OrderedHiddenHttpMethodFilter();
    }
    

    註解@ConditionalOnProperty的詳細屬性如下所示

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Documented
    @Conditional(OnPropertyCondition.class)
    public @interface ConditionalOnProperty {
    
        String[] value() default {}; //數組,獲取對應property名稱的值,與name不可同時使用  
      
        String prefix() default "";//property名稱的前綴,可有可無  
      
        String[] name() default {};//數組,property完整名稱或部分名稱(可與prefix組合使用,組成完整的property名稱),與value不可同時使用  
      
        String havingValue() default "";//可與name組合使用,比較獲取到的屬性值與havingValue給定的值是否相同,相同才加載配置  
      
        boolean matchIfMissing() default false;//缺少該property時是否可以加載。如果爲true,沒有該property也會正常加載;反之報錯  
      
        boolean relaxedNames() default true;//是否可以鬆散匹配,至今不知道怎麼使用的  
    } 
    }
    
    

    matchIfMissing = false表明在application.properties中如果缺少這個property,不會配置HiddenHttpMethodFilter(不知道我理解的是否正確)。因此組合prifixname,在application.properties中添加如下代碼修改默認配置即可

    spring.mvc.hiddenmethod.filter.enabled=true
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章