servlet优化5-在核心控制器中统一获取参数以及视图处理
DispatcherServlet 类
@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet{
private Map<String,Object> 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 beanNodeLists = document.getElementsByTagName("bean");
for (int i = 0;i<beanNodeLists.getLength();i++){
Node beanNode = beanNodeLists.item(i);
//判断该节点的类型是否等于元素节点
if (beanNode.getNodeType() == Node.ELEMENT_NODE){
Element beanElement = (Element)beanNode;
String beanId = beanElement.getAttribute("id");
String className = beanElement.getAttribute("class");
Class controllerBeanClass = Class.forName(className);
Object beanObj = controllerBeanClass.newInstance();
beanMap.put(beanId,beanObj);
}
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置编码
request.setCharacterEncoding("utf-8");
//假设url是:http://localhost:8080/pro15/hello.do
//那么servletPath是: /hello.do
//我的思路是:
///第一步:/hello.do -> hello 或者 /fruit.do -> fruit
//第二步:hello -> HelloController 或者 fruit -> FruitController
String servletPath = request.getServletPath();
servletPath = servletPath.substring(1);
int lastDotIndex = servletPath.lastIndexOf(".do");
servletPath = servletPath.substring(0, lastDotIndex);
Object controllerBeanObj = beanMap.get(servletPath);
String operate = request.getParameter("operate");
if (StringUtil.isEmpty(operate)){
operate = "index";
}
try {
Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();
for (Method method : methods) {
if (operate.equals(method.getName())){
//1.统一获取请求参数
//1-1 获取当前方法的参数,返回参数数组
Parameter[] parameters = method.getParameters();
//1-2 parameterValues 用来存放参数的值
Object[] parameterValues = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
String parameterName = parameter.getName();
//如果参数名是request,response,session,那么就不是通过请求中获取参数的方式
if ("request".equals(parameterName)){
parameterValues[i] = request;
}else if ("response".equals(parameterName)){
parameterValues[i] = response;
}else if ("session".equals(parameterName)){
parameterValues[i] = request.getSession();
}else {
//从请求中获取参数值
String parameterValue = request.getParameter(parameterName);
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" 而不是 2
}
}
method.setAccessible(true);
//2.controller组件中的方法调用
//找到和operate同名的方法,那么通过反射技术调用它
Object returnObj = method.invoke(controllerBeanObj,parameterValues);
//3.视图处理
String methodReturnStr = (String)returnObj;
if (methodReturnStr.startsWith("redirect:")){ //比如:redirect:fruit.do
String redirectStr = methodReturnStr.substring("redirect:".length());
response.sendRedirect(redirectStr);
}else{
super.processTemplate(methodReturnStr,request,response); //比如 : "edit"
}
}
}
// }else {
// throw new RuntimeException("operate的值非法!");
// }
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
//常见错误:IllegalArgumentException: argument type mismatch
FruitController 类
//FruitServlet 改名为 FruitController
public class FruitController{
private FruitDAO fruitDAO = new FruitDaoImpl();
private String update(Integer fid,String fname,Integer price,Integer fcount,String remark){
//3.执行更新
fruitDAO.updateFruit(new Fruit(fid, fname, price, fcount, remark));
//4.资源跳转
//super.processTemplate("index",request,response);
//request.getRequestDispatcher(index.html).forward(request,response);
//此处需要重定向,目的是重新给IndexServlet发请求,重新获取fruitList,然后覆盖到session
//这样index.html页面上显示的session中的数据才是最新的
//response.sendRedirect("fruit.do");
return "redirect:fruit.do";
}
private String edit(Integer fid,HttpServletRequest request){
if (fid != null) {
Fruit fruit = fruitDAO.getFruitByFid(fid);
request.setAttribute("fruit", fruit);
//super.processTemplate("edit", request, response);
return "edit";
}
return "error";
}
private String del(Integer fid){
if (fid != null) {
fruitDAO.delFruit(fid);
//response.sendRedirect("fruit.do");
return "redirect:fruit.do";
}
return "error";
}
private String add(String fname,Integer price,Integer fcount,String remark){
Fruit fruit = new Fruit(0, fname, price, fcount, remark);
fruitDAO.addFruit(fruit);
//response.sendRedirect("fruit.do");
return "redirect:fruit.do";
}
private String index(String oper,String keyword,Integer pageNo,HttpServletRequest request){
HttpSession session = request.getSession();
if (pageNo == null){
pageNo = 1;
}
//如果oper != null 说明是通过表单的查询按钮点击过来的
//如果oper是空的,说明不是通过表单的查询按钮点击过来的
if (StringUtil.isNotEmpty(oper) && "search".equals(oper)) {
//说明是点击表单查询发送过来的请求
//此时,pageNo应该还原为1,keyword应该从请求参数获取
pageNo = 1;
//如果keyword为null,需要设置为空字符串"",否则查询时会拼接成 %null%
//我们期望的是 %%,就是查询所有的数据
if (StringUtil.isEmpty(keyword)) {
keyword = "";
}
//将 keyword 保存(覆盖)到session中
session.setAttribute("keyword", keyword);
} else {
//说明此处不是点击表单查询发送过来的请求(比如点击下面的上一页下一页或者直接在地址栏输入网址)
//此时keyword应该从session作用域获取
//如果不是点击的查询按钮,那么查询是基于session中保存的现有的keyword进行查询
Object keywordobj = session.getAttribute("keyword");
if (keywordobj != null) {
keyword = (String) keywordobj;
} else {
keyword = "";
}
}
//重新更新当前页的值
session.setAttribute("pageNo", pageNo);
FruitDAO fruitDAO = new FruitDaoImpl();
List<Fruit> fruitList = fruitDAO.getFruitList(keyword, pageNo);
session.setAttribute("fruitList", fruitList);
//总记录条数
int fruitCount = fruitDAO.getFruitCount(keyword);
//总页数
int pageCount = (fruitCount + 5 - 1) / 5;
/*
总记录条数 总页数
1 1
5 1
6 2
10 2
11 3
fruitCount (fruitCount+5-1)/5
*/
session.setAttribute("pageCount", pageCount);
//此处的视图名称是index
//那么thymeleaf会将这个 逻辑视图 名称对应到 物理视图 名称上去
// //逻辑视图名称:index
//物理视图名称: viw-prefix + 逻辑视图名称 +view-suffix
//所以真实的视图名称是: / index .html
//super.processTemplate("index", request, response);
return "index";
}
}