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
    
发布了108 篇原创文章 · 获赞 22 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/GoSantiago/article/details/102933349