接上次的 MyBatis 入门书籍,这次实现的是 SpringMVC 的入门测试项目。环境与书中不同的地方是项目管理方式是 Maven、IDE 用了 IDEA。内容包括代码、相关知识解读、遇到的BUG记录及解决方式。
不止有 controller 层和 model 层,cn.com.mvc 中的正确文件层级简单查了下还应该有:dao、cons、domain、exception、service等。继续前进时会遇到,暂时不查那么详细。
项目新建的方法,网上有太多太多了,我就不重复了。直接上代码。
Maven 配置
参考博客:https://www.cnblogs.com/Sinte-Beuve/p/5730553.html
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>groupIdgroupId>
<artifactId>SpringMVCTestartifactId>
<version>1.0-SNAPSHOTversion>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<configuration>
<source>6source>
<target>6target>
configuration>
plugin>
plugins>
build>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>1.7.21version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>4.3.10.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>4.3.10.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>4.3.10.RELEASEversion>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.43version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.2version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
dependencies>
project>
<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">
<servlet>
<servlet-name>SpringMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:SpringMVC.xmlparam-value>
init-param>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-name>
<url-pattern>*.actionurl-pattern>
servlet-mapping>
<welcome-file-list>
<welcome-file>index.jspwelcome-file>
welcome-file-list>
web-app>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc/
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/scheama/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd ">
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter " />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" />
<bean name="/queryFruits_test.action" class="cn.com.mvc.controller.FruitsControllerTest" />
beans>
package cn.com.mvc.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import cn.com.mvc.model.Fruits;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
// 实现 Controlller 接口
public class FruitsControllerTest implements Controller{
private FruitsService fruitsService = new FruitsService();
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws IOException {
// 模拟 Service 获取水果商品列表
List<Fruits> fruitsList = fruitsService.queryFruitsList();
// 返回 ModelAndView
ModelAndView modelAndView = new ModelAndView();
// 相当于request 的 setAttribute,在 JSP 页面中通过 fruitsList 获取数据
modelAndView.addObject("fruitsList", fruitsList);
// 指定视图
modelAndView.setViewName("WEB-INF/jsp/fruits/fruitsList.jsp");
return modelAndView;
}
}
// 模拟 Service 的内部类
class FruitsService {
public List<Fruits> queryFruitsList() {
List<Fruits> fruitsList = new ArrayList<Fruits>();
Fruits apple = new Fruits();
apple.setName("红富士苹果");
apple.setPrice(2.3);
apple.setProducing_area("山东");
Fruits banana = new Fruits();
banana.setName("香蕉");
banana.setPrice(1.5);
banana.setProducing_area("上海");
fruitsList.add(apple);
fruitsList.add(banana);
return fruitsList;
}
}
Handler处理器用到的实体类,位于 cn.com.mvc.model 包中
macOS中set、get方法的快速构建方式:
package cn.com.mvc.model;
public class Fruits {
private String name;
private double price;
private String producing_area;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getProducing_area() {
return producing_area;
}
public void setProducing_area(String producing_area) {
this.producing_area = producing_area;
}
}
<%@ page language="java" contentType="text/html; ISO-8859-1; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>水果列表title>
head>
<body>
<h3>新鲜水果h3>
<table width="500px;" border=1>
<tr>
<td>名称td>
<td>价格td>
<td>产地td>
tr>
<c:forEach items="${fruitsList }" var="fruit">
<tr>
<td>${fruit.name }td>
<td>${fruit.price }td>
<td>${fruit.producing_area }td>
tr>
c:forEach>
table>
body>
html>
最后在本地 http://localhost:8080/TestMayWork/queryFruits_test.action 即可查询到相关的信息
特点:不需开发;
作用:回应前端控制器 DispatcherServlet 的处理器映射器请求,为其寻找处理该请求的 Handler(带拦截器的 Handler);
映射规则:将 bean 的 name 作为 url 进行查找,需要在配置 Handler 时指定 beanname(就是 url);
类型:BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping、ControllerClassNameHandlerMapping;
配置方式:注解方式、非注解方式;
一个 SimpleUrlHandlerMapping 的配置样例:
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="someCheckInceptor1" />
<ref bean="someCheckInceptor2" />
list>
property>
<property name="mappings">
<props>
<prop key="user.action">userControllerprop>
<prop key="product.action">productionControllerprop>
<prop key="other.action">otherControllerprop>
props>
property>
bean>
一个实现 HttpRequestHandler 接口的 Handler 处理器 (非注解方式)
package cn.com.mvc.controller;
import cn.com.mvc.model.Fruits;
import org.springframework.web.HttpRequestHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
public class FruitsControllerTest2 implements HttpRequestHandler{
private FruitsService fruitsService = new FruitsService();
@Override
public void handleRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 模拟 Service 获取水果商品列表
List<Fruits> fruitsList = fruitsService.queryFruitsList();
// 设置模型数据
request.setAttribute("fruitsList", fruitsList);
// 设置转发视图
request.getRequestDispatcher("WEB-INF/jsp/fruits/fruitsList.jsp").forward(request, response);
}
}
实现之前需要将 springmvc.xml 中的 处理器映射器适配器 修改为如下形式
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />
此处可见我注释了之前使用的 SimpleControllerHandlerAdapter
同时, springmvc.xml 也需要做以下内容添加
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/queryFruits_test3.action">fruitsController2prop>
props>
property>
bean>
<bean id="fruitsController2" class="cn.com.mvc.controller.FruitsControllerTest2" />
(写 prop 标签的时候 IDE 会报错因为还没有写 名为 fruitsController2 的 bean,我没慌你呢?)
这样在本地 http://localhost:8080/TestMayWork/queryFruits_test3.action 即可看到相关的信息。
修改后的 FruitsControllerTest2.java
package cn.com.mvc.controller;
import cn.com.mvc.model.Fruits;
import org.springframework.web.HttpRequestHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
public class FruitsControllerTest2 implements HttpRequestHandler{
private FruitsService fruitsService = new FruitsService();
@Override
public void handleRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 模拟 Service 获取水果商品列表
List<Fruits> fruitsList = fruitsService.queryFruitsList();
// 将 fruitsList 转换为 JSON 串
String jsonInfo = convertListToJson(fruitsList);
// 设置返回格式
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
// 写出 JSON 串
response.getWriter().write(jsonInfo);
}
private String convertListToJson(List<Fruits> fruitsList) {
StringBuilder builder = new StringBuilder();
builder.append('[');
for (Fruits fruits:fruitsList) {
builder.append('{');
builder.append("\"name\":\"").append(fruits.getName()).append("\",");
builder.append("\"price\":\"").append(fruits.getPrice()).append("\",");
builder.append("\"producing_area\":\"").append(fruits.getProducing_area()).append("\"");
}
builder.deleteCharAt(builder.length()-1);
builder.append(']');
return builder.toString();
}
}
[http://localhost:8080/TestMayWork/queryFruits_test3.action]效果
[{"name":"红富士苹果","price":"2.3","producing_area":"山东"{"name":"香蕉","price":"1.5","producing_area":"上海]
(ps:写这个方法里面的格式效率很低,不知道有没有什么好的工具代写一下)
一个 Handler 处理器 (注解方式)
FruitsControllerTest3.java
package cn.com.mvc.controller;
import cn.com.mvc.model.Fruits;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
@Controller
public class FruitsControllerTest3 {
private FruitsService fruitsService = new FruitsService();
// 商品查询列表
// @RequestMapping 实现对 queryFruitsList 方法和 url 进行映射,一个方法对应一个 url
// 一般建议将 url 和 方法写成一样
@RequestMapping("/queryFruitsList")
public ModelAndView queryFruitsList() throws Exception {
// 模拟 Service 获取水果商品列表
List<Fruits> fruitsList = fruitsService.queryFruitsList();
// 返回 ModelAndView
ModelAndView modelAndView = new ModelAndView();
// 相当于request 的 setAttribute,在 JSP 页面中通过 fruitsList 获取数据
modelAndView.addObject("fruitsList", fruitsList);
// 指定视图
modelAndView.setViewName("/WEB-INF/jsp/fruits/fruitsList.jsp");
return modelAndView;
}
}
相关配置方式
springmvc.xml 中添加如下的配置:(开发常用,方便简单)
<mvc:annotation-driven>mvc:annotation-driven>
<context:component-scan base-package="cn.com.mvc.controller">context:component-scan>
特点:不需开发;
作用:根据用户在 web 端的请求,请求处理器映射器 Handler Mapping 寻找处理该请求的 Handler;
解读:本身就是一个 Servlet,它的顶级父类是 HttpServlet;
含有 doGet() 和 doPost() 方法;
最核心的功能由 doService 和 doDispatch 实现;
类型:初始化相关处理类的方法、相应 http 请求的方法、执行处理请求的方法;
DispatcherServlet 处理 url 请求的过程:
收到请求之后通过几级 Servlet 类型的父类的处理,最终调用顶级父类的 doDispatch 方法;
doDispatch 方法中,首先检测 request 是否包含多媒体类型,之后检测 processedRequest 对象是否为原始 request,然后将 boolean 结果赋给 multipartRequestParsed 变量;(这段不知所云)
通过 处理器映射器HandlerMapping 查找 Handler;
通过 HandlerExecutionChain 对象获取具体的 Handler 处理器对象;
调用 HandlerAdapter 对象的 handle 方法,将参数传入,handle 方法会根据开发者写好的代码处理,并返回含有反馈结果和结果视图信息的 ModelAndView 对象;
获得 ModelAndView 对象后,会进行视图渲染,将 model 数据填充到 request 域;
问题原因:Maven 包导入正确;多方查找资料,这种情况下找不到 Jar 包的原因是:tomcat 会从 WEB-INF 的 lib 文件中加载 Jar 包,这是这只小猫加载的第一步。我一开始连 lib 的文件夹都没有建的,所以当然错了;
处理方式:https://blog.csdn.net/du_23tiyanwang/article/details/80654313?utm_source=copy
按照这个博主的方式设置即可,如果不成功将就在 WEB-INF 中先建一个 lib 文件夹,然后把 Available Elements 栏中含 Jar 包的文件夹:右键-Put into Output Root,这样 Jar 包就会稳稳进入 lib 中。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc/
http://www.springframework.org/schema/mvc/spring-mvc.xsd 没写版本号哦
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/scheama/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd ">
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" />
这里错了,一开始没仔细看,直接根据提示回车写成了:
<bean class="org.springframework.web.servlet.view.InternalResourceView" />
解决方式:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/scheama/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd ">
至少要写上 mvc 和 context 的配置,并生效(直观一点,IDEA 中变绿)
<mvc:annotation-driven>mvc:annotation-driven>
<context:component-scan base-package="cn.com.mvc.controller">context:component-scan>