View视图
Thymeleaf视图
若没有前缀,则为Thymeleaf视图,若有forward:则为转发视图,若有Redirect:则为重定向视图。
当控制器方法中的视图没有任何前缀时,视图会被设置的配置文件中的视图解析器解析。
Forward转发视图
使用转发技术,在视图的返回值前加forward可以使请求转发给另一个请求,即调用另一个控制器方法。
@RequestMapping (value = "/testForward")
public String testForward () {
//在视图的配置中,若要在一个控制器下调用另一个控制器(转发),就要利用转发技术forward
//使用转发技术,使其调用另一个控制器
//这个就不是ThymeleafView,而是转发视图
//注意这里forward:后的数据必须转到请求,不能直接转到页面
return "forward:/testThymeleafView";
}
转发请求创建的视图为InternalResourceView,而什么前缀都不带的视图叫做ThymeleafView,重定向视图为redirectView
Redirect重定向视图
重定向视图在视图名称以redirect:为前缀,以redirect:为前缀的视图不会被Thymeleaf解析,而是将后面的信息解析,并以重定向的方式请求。
注:转发是由一次请求,第二次请求是在服务器内部发生的,地址栏不变。重定向是两次请求,第二次是自动访问的,地址栏会发生改变。转发过程中,只有一个请求,所以request域中的数据不会删除,但在重定向的过程中,request请求发生了两次,所以request域中存储的数据是不相同的。
@RequestMapping (value = "/testRedirect")
public String testRedirect () {
return "redirect:/testThymeleafView";
}
ViewController视图控制器
当Controller层不需要处理其他的请求,只需要返回最后的视图时,我们可以使用ViewController,即只需要设置视图名称,不需要进行其他操作的时候就可以使用这个控制器。
使用该控制器需要在SpringMVC中进行配置(注意命名空间):
<!-- path路径下就是@RequestMapping的value值,和前端匹配。 -->
<!-- view-name是return的返回值,也就是转到的页面 -->
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
这样配置之后就可以不写@RequestMapping实现一个只有请求功能,不带其他任何功能的Thymeleaf视图跳转。
但注意在进行这个配置之后,所有的Thymeleaf跳转都会失效(404),这时候必须开启MVC的注解驱动才可以让其他页面正常请求
Restful
Get:查询,Post:添加,Put:修改,Delete:删除
Restful提倡统一的设计风格,从前到后各个单词按斜线分开,不使用?作为请求参数的携带。
举例:
原来以不同的方法作为增删改查的四种不同功能,现在以四种不同的请求方式作为不同的功能,例如:
查询:
-
getUserById --> user/1(get请求方式)
-
saveUser --> user(post请求方式)
-
deleteUser --> user/1(delete请求方式)
-
updateUser --> user(put请求方式)
使用Restful实现用户的操作
使用restful风格实现查询操作:
@RequestMapping(value = "/users", method = RequestMethod.GET)
public String getAllUsers() {
System.out.println("假装我查询了所有信息");
return "success";
}
@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
public String getUserById () {
System.out.println("根据用户id查询信息");
return "success";
}
前端:
<a th:href="@{/users}">查询所有用户信息</a><br>
<a th:href="@{/user/1}">根据id查询信息</a><br>
实现添加操作:
@RequestMapping(value = "/user", method = RequestMethod.POST)
public String insertUser (String username, String password) {
System.out.println("添加用户信息:" + username + " " + password);
return "success";
}
前端:
<form th:action="@{/user}" method="post">
用户名:<input type="text" name="username" /><br>
密码:<input type="password" name="password" /><br>
<input type="submit" value="添加信息"><br>
</form>
但要以put和delete实现修改和删除操作时,不可以简单的使用form表单的put和delete请求,还要添加过滤器。
在web.xml文件中配置过滤器:
<!-- 设置put和delete的hiddenHttpMethodFilter-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<!-- 在所有路径下都生效-->
<url-pattern>/*</url-pattern>
</filter-mapping>
注:过滤器方法一定有参数FilterChain来确定是拦截还是放行
过滤器添加之后,在后端使用put方法。
@RequestMapping (value = "/user", method = RequestMethod.PUT)
public String updateUser (String username, String password) {
System.out.println("修改用户信息:" + username + " " + password);
return "success";
}
在前端使用post方法并添加隐藏标签,隐藏标签的name必须设置为_method
,其value值可以设为put或delete
<form th:action="@{/user}" method="post">
<!-- 将真正的请求方式传入,传入一个hidden的input标签,并将其命名为_method,令其value值为真正的请求(put或delete)-->
<input type="hidden" name="_method" value="PUT">
用户名:<input type="text" name="username" /><br>
密码:<input type="password" name="password" /><br>
<input type="submit" value="修改信息"><br>
</form>
RestFul案例
环境配置
设置pom.xml
打包方式设置为war包,并添加依赖。
<dependencies>
<!-- SpringMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.1</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- ServletAPI -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- Spring5和Thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
</dependencies>
添加web.xml
在web.xml文件中配置两个过滤器和前端控制器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 设置编码过滤器-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 设置put和delete的hiddenHttpMethodFilter-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<!-- 在所有路径下都生效-->
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置springMVC前端控制器DispatcherServlet-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 不使用springMVC的默认配置文件,自己进行配置-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
在resources下添加springMVC.xml并进行配置(注意扫描组件的包名要随项目进行更改)、
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 扫描组件-->
<context:component-scan base-package="改这个!!!!!!!!!!!,使用逗号隔开就可以写两个包"></context:component-scan>
<!-- 配置Thymeleaf视图解析器-->
<!-- 配置视图解析器Thymeleaf-->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<!-- Thymeleaf优先级的配置-->
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<!-- 模板-->
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8" />
</bean>
</property>
</bean>
</property>
</bean>
</beans>
首页的配置
因为首页只需要实现一个跳转的功能,故在springMVC.xml文件中直接进行首页的配置:
配置在beans标签下
<!-- 配置视图控制器,即首页的跳转-->
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
<!-- 避免视图控制器的配置影响到其他组件,开启mvc注解驱动-->
<mvc:annotation-driven />
首页的html:
<body>
<h1>首页</h1>
<a th:href="@{/employee}">查看员工信息</a>
</body>
查看所有信息
后端配置(Controller):
@Autowired
private EmployeeDao employeeDao;
@RequestMapping(value = "/employee", method = RequestMethod.GET)
public String getAllEmployees (Model model) {
Collection<Employee> employeeList = employeeDao.getAll();
//向域中添加数据
model.addAttribute("employeeList", employeeList);
return "employee_list";
}
前端配置:
<body>
<table>
<tr>
<!-- 合并五行-->
<th colspan="5">Employee Info</th>
</tr>
<tr>
<th>id</th>
<th>lastname</th>
<th>email</th>
<th>gender</th>
<th>options</th>
</tr>
<!-- 循环集合-->
<tr th:each="employee : ${employeeList}">
<td th:text="${employee.id}"></td>
<td th:text="${employee.lastName}"></td>
<td th:text="${employee.email}"></td>
<td th:text="${employee.gender}"></td>
<td>
<a href="">delete</a>
<a href="">update</a>
</td>
</tr>
</table>
</body>
删除
注意maven中打war包可能会发生类似于Cannot access defaults field of Properties这样的错误,一种解决方式为在POM.xml文件中的paoject标签内添加如下插件:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.1</version>
</plugin>
</plugins>
</build>
再进行packaged就可以成功打包了
删除操作的具体操作
对删除的超链接进行点击事件的绑定并确定转到的Controller层方法
<a @click="deleteEmployee" th:href="@{'/employee/'+${employee.id}}">delete</a>
设置表单来确定delete对应相应的Controller:
<!-- delete按钮来控制表单-->
<form id="deleteForm" method="post">
<input type="hidden" name="_method" value="delete" />
</form>
在vue中确定click方法的内容:
deleteEmployee : function (event) {
//根据id获取表单元素
var deleteForm = document.getElementById("deleteForm");
//将点击事件的href赋值给表单的action
deleteForm.action = event.target.href;
//提交表单
deleteForm.submit();
//取消提交表单的默认行为
//如果不取消,超链接会有默认行为,先跳转页面。
event.preventDefault();
}
后台的delete操作:
@RequestMapping (value = "/employee/{id}", method = RequestMethod.DELETE)
//@PathVariable注解将RequestMapping传进来的id赋值给形参id
public String deleteEmployee(@PathVariable("id") Integer id) {
employeeDao.delete(id);
//因为最后要返回整个页面的请求,所以使用重定向,转发可能会重新读取导致删除看起来有问题
return "redirect:/employee";
}
Dao层的Delete操作:
//相当于从Map中删除了一条记录
public void delete(Integer id){
employees.remove(id);
}
修改
在首页面中进行操作:
将链接赋值:
<a th:href="@{'/employee/'+${employee.id}}">update</a>
跳转到后台Controller层的请求:
//回显功能,使用Get方法
@RequestMapping (value = "/employee/{id}", method = RequestMethod.GET)
public String update(@PathVariable Integer id, Model model) {
Employee emp = employeeDao.get(id);
//添加到域中
model.addAttribute("employee", emp);
return "employee_update";
}
请求跳转到employee_update.html页面
<body>
<form th:action="@{/employee}" method="post">
<!-- 解析实际的请求方式-->
<input type="hidden" name="_method" value="put" />
<input type="hidden" name="id" th:value="${employee.id}" />
lastName:<input type="text" name="lastName" th:value="${employee.lastName}"/><br>
email:<input type="text" name="email" th:value="${employee.email}"/><br>
<!-- 使用th:field操作来对radio标签赋初值-->
gender:<input type="radio" name="gender" value="1" th:field="${employee.gender}"/>male
<input type="radio" name="gender" value="0" th:field="${employee.gender}"/>female<br>
<input type="submit" value="UPDATE"/>
</form>
再响应到Controller层中的update方法
@RequestMapping (value = "/employee", method = RequestMethod.PUT)
public String updateEmployee(Employee emp) {
employeeDao.save(emp);
return "redirect:/employee";
}
最终调用Dao层的方法对数据进行修改