将所有Servlet合并为一个
1.新建FruitServlet合并Servlet
2.修改指向其他Servlet的代码,指向FruitServlet,同时传operate参数指明采用什么操作(如add,del,update等)
① FruitServlet
package com.example.myssm.servlets;
import com.example.fruit.dao.FruitDAO;
import com.example.fruit.dao.impl.FruitDAOImpl;
import com.example.fruit.pojo.Fruit;
import com.example.myssm.myspringmvc.ViewBaseServlet;
import com.example.myssm.util.StringUtil;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
@WebServlet("/fruit.do")
public class FruitServlet extends ViewBaseServlet {
private FruitDAO fruitDAO = new FruitDAOImpl();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置编码
req.setCharacterEncoding("utf-8");
String operate = req.getParameter("operate");
if(StringUtil.isEmpty(operate)){
operate = "index";
}
switch(operate){
case "index":
index(req,resp);
break;
case "add":
add(req,resp);
break;
case "del":
del(req,resp);
break;
case "edit":
edit(req,resp);
break;
case "update":
update(req,resp);
break;
default:
throw new RuntimeException("operate值非法");
}
}
//UpdateServlet的doPost
protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//2 获取参数
String fidStr = req.getParameter("fid");
int fid = Integer.parseInt(fidStr);
String fname = req.getParameter("fname");
String priceStr = req.getParameter("price");
int price = Integer.parseInt(priceStr);
String fcountStr = req.getParameter("fcount");
int fcount = Integer.parseInt(fcountStr);
String remark = req.getParameter("remark");
//3 执行更新
fruitDAO.updateFruit(new Fruit(fid,fname,price,fcount,remark));
//4 资源跳转
// super.processTemplate("index",req,resp);
//req.getRequestDispatcher("inex.html").forward(req,resp);
//此处需要重定向,目的是重新给IndexServlet发请求,重新获取fruitList,然后覆盖到session
resp.sendRedirect("fruit.do");
}
//EditServlet得到doGet
protected void edit(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String fidStr = req.getParameter("fid");
if(StringUtil.isNotEmpty(fidStr)){
int fid = Integer.parseInt(fidStr);
Fruit fruit = fruitDAO.getFruitByFid(fid);
req.setAttribute("fruit",fruit);
super.processTemplate("edit",req,resp);
}
}
//delServlet的doGet
protected void del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String fidStr = req.getParameter("fid");
if(StringUtil.isNotEmpty(fidStr)){
int fid = Integer.parseInt(fidStr);
fruitDAO.delFruit(fid);
resp.sendRedirect("fruit.do");
}
}
//addServlet的doPost
protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String fname = req.getParameter("fname");
String priceStr = req.getParameter("price");
Integer price = Integer.parseInt(priceStr);
String fcountStr = req.getParameter("fcount");
Integer fcount = Integer.parseInt(fcountStr);
String remark = req.getParameter("remark");
fruitDAO.addFruit(new Fruit(0,fname,price,fcount,remark));
resp.sendRedirect("fruit.do");
}
//indexServlet的doGet
protected void index(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Integer pageNo = 1;
String oper = req.getParameter("oper");
//如果oper!=null 说明,通过表单的查询按钮的过来的
//如果oper是空的,说明,不是通过表单的查询按钮点过来的
HttpSession session = req.getSession();
String keyword = null;
if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){
//说明是点击表单查询发送过来的请求
//此时,pageNo应该还原为1,keyword应该从请求参数中获取
pageNo = 1;
keyword = req.getParameter("keyword");
if(StringUtil.isEmpty(keyword)){
keyword = "";
}
session.setAttribute("keyword",keyword);
}else{
//说明此处不是点击表单查询发送的请求
String pageNoStr = req.getParameter("pageNo");
if(StringUtil.isNotEmpty(pageNoStr)){
pageNo = Integer.parseInt(pageNoStr);
}
Object keywordObj = session.getAttribute("keyword");
if(keywordObj!=null){
keyword = (String) keywordObj;
}else{
keyword = "";
}
}
session.setAttribute("pageNo",pageNo);
FruitDAO fruitDAO = new FruitDAOImpl();
List fruitList = fruitDAO.getFruitList(keyword,pageNo);
//保存到session作用域
session.setAttribute("fruitList",fruitList);
//总记录条数
int fruitCount = fruitDAO.getFruitCount(keyword);
//总页数
int pageCount = (fruitCount+5-1)/5;
session.setAttribute("pageCount",pageCount);
//此处的视图名称是index
//thymeleaf会将这个 逻辑视图名称 对应的 物理视图 名称上去
//逻辑视图名称:index
//物理视图名称:view-prefix + 逻辑视图名称 + view-suffix
//所以真实的视图名称是:/ index .html
super.processTemplate("index",req,resp);
}
}
② 修改index.html(index、查询、edit)
③ 修改add1.html(add)
编辑库存信息
④修改edit.xml(update)
编辑库存信息
⑤修改index.js(del、分页)
function delFruit(fid){
if(confirm("是否确认删除?")){
window.location.href='fruit.do?fid='+fid+'&operate=del';
}
}
function page(pageNo){
window.location.href="fruit.do?pageNo="+pageNo;
}
2.mvc-servlet优化2——reflect
采用反射机制优化FruitServlet
当存在很多方法时,写switch-case显得冗余,使用反射能很好的解决这一问题,而不需要关心具体有多少方法
修改FruitServlet的service方法
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置编码
req.setCharacterEncoding("utf-8");
String operate = req.getParameter("operate");
if(StringUtil.isEmpty(operate)){
operate = "index";
}
//获取当前类中所有的方法
Method[] methods = this.getClass().getDeclaredMethods();
for (Method m : methods) {
//获取方法名称
String methodName = m.getName();
if(operate.equals(methodName)){
try {
//找到和operate同名的方法,那么通过反射技术调用它
m.invoke(this,req,resp);
return ;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
throw new RuntimeException("operate值非法");
}
3.mvc-servlet优化3——dispatcherServlet引入
dispatcherServlet(中央控制器、核心控制器)
通过dispatcherServlet去调用不同的Servlet(如userServlert,FruitServlet等)
①在java包下新建applicationContext.xml
②重命名FruitServlet为FruitController并修改(FruitController变为普通的类)
package com.example.myssm.servlets;
import com.example.fruit.dao.FruitDAO;
import com.example.fruit.dao.impl.FruitDAOImpl;
import com.example.fruit.pojo.Fruit;
import com.example.myssm.myspringmvc.ViewBaseServlet;
import com.example.myssm.util.StringUtil;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
public class FruitController extends ViewBaseServlet {
//之前FruitServlet是一个Servlet组件,那么其中的init方法一定会被调用
//之前的init方法内部有:super.init();
private FruitDAO fruitDAO = new FruitDAOImpl();
//UpdateServlet的doPost
protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//2 获取参数
String fidStr = req.getParameter("fid");
int fid = Integer.parseInt(fidStr);
String fname = req.getParameter("fname");
String priceStr = req.getParameter("price");
int price = Integer.parseInt(priceStr);
String fcountStr = req.getParameter("fcount");
int fcount = Integer.parseInt(fcountStr);
String remark = req.getParameter("remark");
//3 执行更新
fruitDAO.updateFruit(new Fruit(fid,fname,price,fcount,remark));
//4 资源跳转
// super.processTemplate("index",req,resp);
//req.getRequestDispatcher("inex.html").forward(req,resp);
//此处需要重定向,目的是重新给IndexServlet发请求,重新获取fruitList,然后覆盖到session
resp.sendRedirect("fruit.do");
}
//EditServlet得到doGet
protected void edit(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String fidStr = req.getParameter("fid");
if(StringUtil.isNotEmpty(fidStr)){
int fid = Integer.parseInt(fidStr);
Fruit fruit = fruitDAO.getFruitByFid(fid);
req.setAttribute("fruit",fruit);
super.processTemplate("edit",req,resp);
}
}
//delServlet的doGet
protected void del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String fidStr = req.getParameter("fid");
if(StringUtil.isNotEmpty(fidStr)){
int fid = Integer.parseInt(fidStr);
fruitDAO.delFruit(fid);
resp.sendRedirect("fruit.do");
}
}
//addServlet的doPost
protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String fname = req.getParameter("fname");
String priceStr = req.getParameter("price");
Integer price = Integer.parseInt(priceStr);
String fcountStr = req.getParameter("fcount");
Integer fcount = Integer.parseInt(fcountStr);
String remark = req.getParameter("remark");
fruitDAO.addFruit(new Fruit(0,fname,price,fcount,remark));
resp.sendRedirect("fruit.do");
}
//indexServlet的doGet
protected void index(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Integer pageNo = 1;
String oper = req.getParameter("oper");
//如果oper!=null 说明,通过表单的查询按钮的过来的
//如果oper是空的,说明,不是通过表单的查询按钮点过来的
HttpSession session = req.getSession();
String keyword = null;
if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){
//说明是点击表单查询发送过来的请求
//此时,pageNo应该还原为1,keyword应该从请求参数中获取
pageNo = 1;
keyword = req.getParameter("keyword");
if(StringUtil.isEmpty(keyword)){
keyword = "";
}
session.setAttribute("keyword",keyword);
}else{
//说明此处不是点击表单查询发送的请求
String pageNoStr = req.getParameter("pageNo");
if(StringUtil.isNotEmpty(pageNoStr)){
pageNo = Integer.parseInt(pageNoStr);
}
Object keywordObj = session.getAttribute("keyword");
if(keywordObj!=null){
keyword = (String) keywordObj;
}else{
keyword = "";
}
}
session.setAttribute("pageNo",pageNo);
FruitDAO fruitDAO = new FruitDAOImpl();
List fruitList = fruitDAO.getFruitList(keyword,pageNo);
//保存到session作用域
session.setAttribute("fruitList",fruitList);
//总记录条数
int fruitCount = fruitDAO.getFruitCount(keyword);
//总页数
int pageCount = (fruitCount+5-1)/5;
session.setAttribute("pageCount",pageCount);
//此处的视图名称是index
//thymeleaf会将这个 逻辑视图名称 对应的 物理视图 名称上去
//逻辑视图名称:index
//物理视图名称:view-prefix + 逻辑视图名称 + view-suffix
//所以真实的视图名称是:/ index .html
super.processTemplate("index",req,resp);
}
}
③新建DispatcherServlet类
获取所有applicationContext.xml中存的类并保存在beanMap中,根据传入的ServletPath来调用不同Controller(原Servlet)的方法
package com.example.myssm.myspringmvc;
import com.example.myssm.util.StringUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
@WebServlet("*.do")
public class DispatcherServlet extends HttpServlet {
private Map beanMap = new HashMap<>();
public DispatcherServlet(){
try {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
//1.创建DocumentBuilderFactory
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
//2.创建documentBuilder对象
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
//3.创建Document对象
Document document = documentBuilder.parse(inputStream);
//4.获取所有的bean节点
NodeList beanNodeList = document.getElementsByTagName("bean");
for(int i = 0;i < beanNodeList.getLength();i++){
Node beanNode = beanNodeList.item(i);
if(beanNode.getNodeType() == Node.ELEMENT_NODE){
Element beanElement = (Element) beanNode;
String beanId = beanElement.getAttribute("id");
String className = beanElement.getAttribute("class");
Object beanObj = Class.forName(className).newInstance();
beanMap.put(beanId,beanObj);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置编码
req.setCharacterEncoding("utf-8");
//假设url是 http://localhost:8080/hello.do
//那么servletPath是:/hello.do
//思路是:
//1./hello.do -> hello
//2.hello -> HelloController
String servletPath = req.getServletPath();
// System.out.println("servletPath = " + servletPath); //servletPath = /hello.do
int lastDotIndex = servletPath.lastIndexOf(".do");
servletPath = servletPath.substring(1,lastDotIndex);
// System.out.println(servletPath); //hello
Object controllerBeanObj = beanMap.get(servletPath);
String operate = req.getParameter("operate");
if(StringUtil.isEmpty(operate)){
operate = "index";
}
try {
Method method = controllerBeanObj.getClass().getDeclaredMethod(operate, HttpServletRequest.class, HttpServletResponse.class);
if(method!=null){
method.setAccessible(true);
method.invoke(controllerBeanObj,req,resp);
}else{
throw new RuntimeException("operate值非法");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
④ 由于FruitController没有调用构造器,因此没有调用父类ViewBaseServlet的init()方法,因此暂时无法正常运行,在下一节解决
4.mvc-servlet优化4——提取视图资源处理通用代码解决上节资源跳转问题,将资源跳转放在DispatcherServlet中,且让DispatcherServlet继承ViewBaseServlet即可
① 修改FruitController(将资源跳转操作改为返回字符串,用于说明进行什么操作)
package com.example.myssm.servlets;
import com.example.fruit.dao.FruitDAO;
import com.example.fruit.dao.impl.FruitDAOImpl;
import com.example.fruit.pojo.Fruit;
import com.example.myssm.myspringmvc.ViewBaseServlet;
import com.example.myssm.util.StringUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.List;
public class FruitController{
private FruitDAO fruitDAO = new FruitDAOImpl();
//UpdateServlet的doPost
protected String update(HttpServletRequest req){
//2 获取参数
String fidStr = req.getParameter("fid");
int fid = Integer.parseInt(fidStr);
String fname = req.getParameter("fname");
String priceStr = req.getParameter("price");
int price = Integer.parseInt(priceStr);
String fcountStr = req.getParameter("fcount");
int fcount = Integer.parseInt(fcountStr);
String remark = req.getParameter("remark");
//3 执行更新
fruitDAO.updateFruit(new Fruit(fid,fname,price,fcount,remark));
//4 资源跳转
// super.processTemplate("index",req,resp);
//req.getRequestDispatcher("inex.html").forward(req,resp);
//此处需要重定向,目的是重新给IndexServlet发请求,重新获取fruitList,然后覆盖到session
// resp.sendRedirect("fruit.do");
return "redirect:fruit.do";
}
//EditServlet得到doGet
protected String edit(HttpServletRequest req){
String fidStr = req.getParameter("fid");
if(StringUtil.isNotEmpty(fidStr)){
int fid = Integer.parseInt(fidStr);
Fruit fruit = fruitDAO.getFruitByFid(fid);
req.setAttribute("fruit",fruit);
// super.processTemplate("edit",req,resp);
return "edit";
}
return "error";
}
//delServlet的doGet
protected String del(HttpServletRequest req) {
String fidStr = req.getParameter("fid");
if(StringUtil.isNotEmpty(fidStr)){
int fid = Integer.parseInt(fidStr);
fruitDAO.delFruit(fid);
// resp.sendRedirect("fruit.do");
return "redirect:fruit.do";
}
return "error";
}
//addServlet的doPost
protected String add(HttpServletRequest req){
String fname = req.getParameter("fname");
String priceStr = req.getParameter("price");
Integer price = Integer.parseInt(priceStr);
String fcountStr = req.getParameter("fcount");
Integer fcount = Integer.parseInt(fcountStr);
String remark = req.getParameter("remark");
fruitDAO.addFruit(new Fruit(0,fname,price,fcount,remark));
// resp.sendRedirect("fruit.do");
return "redirect:fruit.do";
}
//indexServlet的doGet
protected String index(HttpServletRequest req) {
Integer pageNo = 1;
String oper = req.getParameter("oper");
//如果oper!=null 说明,通过表单的查询按钮的过来的
//如果oper是空的,说明,不是通过表单的查询按钮点过来的
HttpSession session = req.getSession();
String keyword = null;
if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){
//说明是点击表单查询发送过来的请求
//此时,pageNo应该还原为1,keyword应该从请求参数中获取
pageNo = 1;
keyword = req.getParameter("keyword");
if(StringUtil.isEmpty(keyword)){
keyword = "";
}
session.setAttribute("keyword",keyword);
}else{
//说明此处不是点击表单查询发送的请求
String pageNoStr = req.getParameter("pageNo");
if(StringUtil.isNotEmpty(pageNoStr)){
pageNo = Integer.parseInt(pageNoStr);
}
Object keywordObj = session.getAttribute("keyword");
if(keywordObj!=null){
keyword = (String) keywordObj;
}else{
keyword = "";
}
}
session.setAttribute("pageNo",pageNo);
FruitDAO fruitDAO = new FruitDAOImpl();
List fruitList = fruitDAO.getFruitList(keyword,pageNo);
//保存到session作用域
session.setAttribute("fruitList",fruitList);
//总记录条数
int fruitCount = fruitDAO.getFruitCount(keyword);
//总页数
int pageCount = (fruitCount+5-1)/5;
session.setAttribute("pageCount",pageCount);
//此处的视图名称是index
//thymeleaf会将这个 逻辑视图名称 对应的 物理视图 名称上去
//逻辑视图名称:index
//物理视图名称:view-prefix + 逻辑视图名称 + view-suffix
//所以真实的视图名称是:/ index .html
// super.processTemplate("index",req,resp);
return "index";
}
}
② DispatcherServlet(继承ViewBaseServlet,完成ViewBaseServlet的inie(),完成资源跳转)
package com.example.myssm.myspringmvc;
import com.example.myssm.util.StringUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {
private Map beanMap = new HashMap<>();
public DispatcherServlet(){
}
public void init() throws ServletException {
super.init();
try {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
//1.创建DocumentBuilderFactory
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
//2.创建documentBuilder对象
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder() ;
//3.创建Document对象
Document document = documentBuilder.parse(inputStream);
//4.获取所有的bean节点
NodeList beanNodeList = document.getElementsByTagName("bean");
for(int i = 0;i < beanNodeList.getLength();i++){
Node beanNode = beanNodeList.item(i);
if(beanNode.getNodeType() == Node.ELEMENT_NODE){
Element beanElement = (Element) beanNode;
String beanId = beanElement.getAttribute("id");
String className = beanElement.getAttribute("class");
Object beanObj = Class.forName(className).newInstance();
beanMap.put(beanId,beanObj);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置编码
req.setCharacterEncoding("utf-8");
//假设url是 http://localhost:8080/hello.do
//那么servletPath是:/hello.do
//思路是:
//1./hello.do -> hello
//2.hello -> HelloController
String servletPath = req.getServletPath();
// System.out.println("servletPath = " + servletPath); //servletPath = /hello.do
int lastDotIndex = servletPath.lastIndexOf(".do");
servletPath = servletPath.substring(1,lastDotIndex);
// System.out.println(servletPath); //hello
Object controllerBeanObj = beanMap.get(servletPath);
String operate = req.getParameter("operate");
if(StringUtil.isEmpty(operate)){
operate = "index";
}
try {
Method method = controllerBeanObj.getClass().getDeclaredMethod(operate, HttpServletRequest.class);
if(method!=null){
//2.Controller组件中的方法调用
method.setAccessible(true);
Object returnObj = method.invoke(controllerBeanObj,req);
//3.视图处理
String methodReturnStr = (String) returnObj;
if(methodReturnStr.startsWith("redirect:")){//如:redirect:fruit.do
String redirectStr = methodReturnStr.substring("redirect:".length());
resp.sendRedirect(redirectStr);
}else{
super.processTemplate(methodReturnStr,req,resp); //如:"edit"
}
}else{
throw new RuntimeException("operate值非法");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
5.mvc-servlet优化5——在核心控制器中统一获取参数及视图处理
参数的获取在DispatcherServlet中完成
① 获取参数的实际名称,对idea进行设置(jdk8 新特性)
② 删除out文件夹下的文件然后重新build
③ 修改FruitController的方法为参数传入的方式
package com.example.myssm.servlets;
import com.example.fruit.dao.FruitDAO;
import com.example.fruit.dao.impl.FruitDAOImpl;
import com.example.fruit.pojo.Fruit;
import com.example.myssm.util.StringUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.List;
public class FruitController{
private FruitDAO fruitDAO = new FruitDAOImpl();
//UpdateServlet的doPost
protected String update(Integer fid,String fname ,Integer price,Integer fcount,String remark){
//3 执行更新
fruitDAO.updateFruit(new Fruit(fid,fname,price,fcount,remark));
//4 资源跳转
// resp.sendRedirect("fruit.do");
return "redirect:fruit.do";
}
//EditServlet得到doGet
protected String edit(Integer fid,HttpServletRequest req){
if(fid != null){
Fruit fruit = fruitDAO.getFruitByFid(fid);
req.setAttribute("fruit",fruit);
// super.processTemplate("edit",req,resp);
return "edit";
}
return "error";
}
//delServlet的doGet
protected String del(Integer fid) {
if(fid != null){
fruitDAO.delFruit(fid);
// resp.sendRedirect("fruit.do");
return "redirect:fruit.do";
}
return "error";
}
//addServlet的doPost
protected String add(Integer fid,String fname ,Integer price,Integer fcount,String remark){
fruitDAO.addFruit(new Fruit(0,fname,price,fcount,remark));
// resp.sendRedirect("fruit.do");
return "redirect:fruit.do";
}
//indexServlet的doGet
protected String index(String oper,String keyword,Integer pageNo,HttpServletRequest req) {
System.out.println(req);
HttpSession session = req.getSession();
if(pageNo == null){
pageNo = 1;
}
if(StringUtil.isNotEmpty(oper) && "search".equals(oper)){
//说明是点击表单查询发送过来的请求
//此时,pageNo应该还原为1,keyword应该从请求参数中获取
pageNo = 1;
if(StringUtil.isEmpty(keyword)){
keyword = "";
}
session.setAttribute("keyword",keyword);
}else{
Object keywordObj = session.getAttribute("keyword");
if(keywordObj!=null){
keyword = (String) keywordObj;
}else{
keyword = "";
}
}
session.setAttribute("pageNo",pageNo);
FruitDAO fruitDAO = new FruitDAOImpl();
List fruitList = fruitDAO.getFruitList(keyword,pageNo);
//保存到session作用域
session.setAttribute("fruitList",fruitList);
//总记录条数
int fruitCount = fruitDAO.getFruitCount(keyword);
//总页数
int pageCount = (fruitCount+5-1)/5;
session.setAttribute("pageCount",pageCount);
// super.processTemplate("index",req,resp);
return "index";
}
}
④ 修改DispatcherServlet获取参数
package com.example.myssm.myspringmvc;
import com.example.myssm.util.StringUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {
private Map beanMap = new HashMap<>();
public DispatcherServlet(){
}
public void init() throws ServletException {
super.init();
try {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
//1.创建DocumentBuilderFactory
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
//2.创建documentBuilder对象
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder() ;
//3.创建Document对象
Document document = documentBuilder.parse(inputStream);
//4.获取所有的bean节点
NodeList beanNodeList = document.getElementsByTagName("bean");
for(int i = 0;i < beanNodeList.getLength();i++){
Node beanNode = beanNodeList.item(i);
if(beanNode.getNodeType() == Node.ELEMENT_NODE){
Element beanElement = (Element) beanNode;
String beanId = beanElement.getAttribute("id");
String className = beanElement.getAttribute("class");
Object beanObj = Class.forName(className).newInstance();
beanMap.put(beanId,beanObj);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置编码
req.setCharacterEncoding("utf-8");
//假设url是 http://localhost:8080/hello.do
//那么servletPath是:/hello.do
//思路是:
//1./hello.do -> hello
//2.hello -> HelloController
String servletPath = req.getServletPath();
// System.out.println("servletPath = " + servletPath); //servletPath = /hello.do
int lastDotIndex = servletPath.lastIndexOf(".do");
servletPath = servletPath.substring(1,lastDotIndex);
// System.out.println(servletPath); //hello
Object controllerBeanObj = beanMap.get(servletPath);
String operate = req.getParameter("operate");
if(StringUtil.isEmpty(operate)){
operate = "index";
}
try {
Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();
for (Method method : methods) {
if(operate.equals(method.getName())){
//1.统一获取请求参数
//获取当前方法的参数,返回参数数组
Parameter[] parameters = method.getParameters();
//parameterValues 用来承载参数的值
Object[] parameterValues = new Object[parameters.length];
for(int i = 0;i < parameters.length;i++){
Parameter parameter = parameters[i];
String parameterName = parameter.getName();
if("req".equals(parameterName)){
//如果参数名是req,resp,session 那么久不是通过请求中获取参数的方式了
parameterValues[i] = req;
}else if("resp".equals(parameterName)) {
parameterValues[i] = resp;
}else if("session".equals(parameterName)) {
parameterValues[i] = req.getSession();
}else{
//从请求中获取参数值
String parameterValue = req.getParameter(parameterName);
//类型转换 避免错误: IllegalArgumentException: argument type mismatch
String typeName = parameter.getType().getName();
Object parameterObj = parameterValue;
if(parameterObj != null){
if("java.lang.Integer".equals(typeName)){
parameterObj = Integer.parseInt(parameterValue);
}
}
parameterValues[i] = parameterObj;
}
}
//2.Controller组件中的方法调用
method.setAccessible(true);
Object returnObj = method.invoke(controllerBeanObj,parameterValues);
//3.视图处理
String methodReturnStr = (String) returnObj;
if(methodReturnStr.startsWith("redirect:")){//如:redirect:fruit.do
String redirectStr = methodReturnStr.substring("redirect:".length());
resp.sendRedirect(redirectStr);
}else{
super.processTemplate(methodReturnStr,req,resp); //如:"edit"
}
}
}
// }else{
// throw new RuntimeException("operate值非法");
// }
} catch (Exception e) {
e.printStackTrace();
}
}
}
⑤ 启动tomcat容器,访问:http://localhost:8080/fruit.do
若出现问题:java.lang.IllegalArgumentException: InputStream cannot be null
将applicationContext.xml移动到resources包下
- 最初的做法是: 一个请求对应一个Servlet,这样存在的问题是servlet太多了
- 把一些列的请求都对应一个Servlet, IndexServlet/AddServlet/EditServlet/DelServlet/UpdateServlet -> 合并成FruitServlet
通过一个operate的值来决定调用FruitServlet中的哪一个方法
使用的是switch-case - 在上一个版本中,Servlet中充斥着大量的switch-case,试想一下,随着我们的项目的业务规模扩大,那么会有很多的Servlet,也就意味着会有很多的switch-case,这是一种代码冗余
因此,我们在servlet中使用了反射技术,我们规定operate的值和方法名一致,那么接收到operate的值是什么就表明我们需要调用对应的方法进行响应,如果找不到对应的方法,则抛异常 - 在上一个版本中我们使用了反射技术,但是其实还是存在一定的问题:每一个servlet中都有类似的反射技术的代码。因此继续抽取,设计了中央控制器类:DispatcherServlet
DispatcherServlet这个类的工作分为两大部分:
1.根据url定位到能够处理这个请求的controller组件:
1)从url中提取servletPath : /fruit.do -> fruit
2)根据fruit找到对应的组件:FruitController , 这个对应的依据我们存储在applicationContext.xml中



