现在的业务流程
现在我们只是对于fruit一张表进行操作,我们的业务流程如下图
如果我们还要对于其他的数据表进行操作的话,业务会非常混乱,所以现在我们需要对于业务逻辑进行优化
优化业务流程1.0
我们现在希望一张表只对应一个servlet,在这个servlet的service方法中实现对于这张表所有的操作。对于其他表,再新servlet就可以了
在FruitServlet里重写service方法
把原本indexServlet里重写的doget复制到FruitServlet的service下面,改名字,并且把设置编码放到service里面
我们重新定义一个operate(用于存放前端现在想访问哪个方法实现功能),获取operate再用swiitch判断现在要执行什么方法,如果现在要执行index,就调用下面的index方法就可以了,其他的以此类推
注意:如果operate为空,就默认访问index就可以了
例如:
我们原本写的其他的方法类似,我们都把它们复制到下面并且加入switch,但是我们加add的时候,我们需要newFruitDAOImpl对象,我们直接在整个代码刚开始加就可以了
把其他的加完后,之前写的就可以删除了
现在我们整个服务器的焦点都在operate上面了,我们只需要控制前端给后端页面申请的页面,改成我们当前operate需要后端调用的方法就可以了
index.html的修改:
1.展示数据
之前点击是跳转到edit.do,现在应该是fruit.do,而且现在应该传operate过去
执行完edit后,跳转到edit.html页面
2.删除数据
之前点击是跳转到del.do,现在应该是fruit.do,而且现在应该传operate过去
跳转后执行del方法,我们原本最后是重定向到index代码,原本的index最后会帮我们处理渲染数据,现在跳转到fruit.do,开始获取operate,但是一开始我们的operate没有存作用域,这次的operate就是null,所以默认执行index方法,index最后渲染数据,一样的
3.点击上下页
我们写的跳转在JS里
之前点击是跳转到index,现在应该是fruit.do,不要传operate了,不传默认就是执行index方法
3.进行模糊查询的表单提交
之前点击是跳转到add.do,现在应该是fruit.do
add.html的修改:
1.表单提交
之前点击是跳转到add.do,现在应该是fruit.do,而且要用隐藏域传operate
执行结束add后,原本重定向到index,现在应该再重定向到fruit.do
edit.html的修改:
1.修改后的表单提交
之前点击是跳转到update.do,现在应该是fruit.do,而且要用隐藏域传operate
执行结束update后,原本重定向到index,现在应该再重定向到fruit.do
测试:
成功,功能没有问题
优化业务流程2.0
我的的1.0版本,如果fruitServlet里的方法很多,service方法里的switch方法就会非常多,有没有合理的方法让这段代码优化?
利用反射技术
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//设置编码
req.setCharacterEncoding("UTF-8");
String operate = req.getParameter("operate");
if (StringUtil.isEmpty(operate)){
operate = "index";
}
//获取当前类中所有的方法集合
Method[] methods = this.getClass().getDeclaredMethods();
//通过增强for循环,来对比operate和methods里的每一个元素,如果相同,就执行对应的方法
for(Method m : methods){
//获取当前循环的方法名
String methodName = m.getName();
if (operate.equals(methodName)){
//找到后通过反射技术调用
try {
m.invoke(this,request,response);
//找到并且执行结束后,直接return就可以了
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
//如果所有方法名都没有对应,说明当前operate值不对
throw new RuntimeException("operate值非法");
}
成功,功能没有问题
优化业务流程3.0:
之前我们完成了对一张表上所有方法的汇总,现在想对这张表操作,只需要操作servlet就可以了,但是如果我们的表非常多怎么办呢?我们引入中央控制器dispatcher,所有的请求都交给这个dispatcher,dispatcher再去找对应的表的对应的方法,结构就会很清晰了,现在的问题是,该如何实现这个dispatcher
为了引入MVC现在把我们原本写的servlet都要改成contriller
实现思路:
我们可以通过@webservlet("/*.do")来拦截我们所有以.do为结尾的请求,通过字符串截取看先现在想对哪个表进行操作,截取后想办法把字符串和我们对应的controller对应
因为所有请求都j经过dispatcher,我们在dispatcher这边设置编码就可以了
1.截取字符串:
在控制器拦截所有请求:(所以之前fruitController里的web注解要去掉,此时fruitController就已经不是一个servlet组件了)
获取当前拦截到的是什么东西
String servletPath = req.getServletPath();
去掉拦截到的第一个,也即是‘“ ”
servletPath = servletPath.substring(1);
看看“ .do ”在第几个位置
int lastDotIndex = servletPath.lastIndexOf(".do");
去掉“ .do ”就是我们要的东西
servletPath = servletPath.substring(0, lastDotIndex);
代码:
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String servletPath = req.getServletPath();
servletPath = servletPath.substring(1);
int lastDotIndex = servletPath.lastIndexOf(".do");
servletPath = servletPath.substring(0, lastDotIndex);
}
2.截取字符串和我们对应的controller对应(用xml文件)
在src下新建一个
xml是什么东西?
为什么写的是beans标签呢?
bean对应着java中的一个对象,我有很多个对象,就把他们放到beans里
这样子就表明了,如果以后要给furit发请求,就要交给FruitController来处理
现在我们xml文件写好了,问题是该如何在我们代码的地方读取到这个配置文件呢
专门写一个方法来解析配置文件
我们要利用document对象来获取xml文件输入流
//获取文件流
InputStream inputStream =
getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
//创建DocumentBuilderFactory对象
DocumentBuilderFactory documentBuilderFactory =
DocumentBuilderFactory.newInstance();
//创建documentBuilder对象
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
//创建document对象
Document document = documentBuilder.parse(inputStream);
利用document对象里的方法获取xml文件里所有bean标签并且生成一个集合,循环遍历我们的集合,如果当前元素是bean标签(元素标签),就把它的id和class存起来,我们可以用Map存储,但是现在我们class想对应的是实例对象,所以要用forname反射把当前的class实例化
public DispatcherServlet(){
try {
//获取文件流
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
//创建DocumentBuilderFactory对象
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
//创建documentBuilder对象
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
//创建document对象
Document document = documentBuilder.parse(inputStream);
//利用document对象里的方法获取xml文件里所有bean标签并且生成一个集合
NodeList beanNodeList = document.getElementsByTagName("bean");
System.out.println(beanNodeList);
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");
//System.out.println(beanId);
String className = beanElement.getAttribute("class");
Object beanObj = Class.forName(className).newInstance();
//System.out.println(beanObj.getClass ().getSimpleName ());
beanMap.put(beanId, beanObj);
}
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
之后再在我们的service方法中就可以通过id来获取实例对象了
Object controllerBeanObj = beanMap.get(servletPath);
再把原来FruitController里判断当前要执行什么方法的代码放到service里就行了,但是原本反射调用this,现在就要用controllerBeanObj
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String servletPath = req.getServletPath();
servletPath = servletPath.substring(1);
int lastDotIndex = servletPath.lastIndexOf(".do");
servletPath = servletPath.substring(0, lastDotIndex);
//找到当前执行的是哪张表(id),获取对应的实例化对象(class)
Object controllerBeanObj = beanMap.get(servletPath);
//找到当前对应类中要执行哪个方法
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//设置编码
req.setCharacterEncoding("UTF-8");
String operate = req.getParameter("operate");
if (StringUtil.isEmpty(operate)){
operate = "index";
}
//获取当前类中所有的方法集合
Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();
//通过增强for循环,来对比operate和methods里的每一个元素,如果相同,就执行对应的方法
for(Method m : methods){
//获取当前循环的方法名
String methodName = m.getName();
if (operate.equals(methodName)){
//找到后通过反射技术调用
try {
m.invoke(this,request,response);
//找到并且执行结束后,直接return就可以了
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
//如果所有方法名都没有对应,说明当前operate值不对
throw new RuntimeException("operate值非法");
}
但是现在调用方法的代码还是太过于长,可以通过反射更好的方法,只获取当前operate对应的方法就可以,如果找到的方法不为空,就执行,为空就抛异常
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String servletPath = req.getServletPath();
servletPath = servletPath.substring(1);
int lastDotIndex = servletPath.lastIndexOf(".do");
servletPath = servletPath.substring(0, lastDotIndex);
//找到当前执行的是哪张表(id),获取对应的实例化对象(class)
Object controllerBeanObj = beanMap.get(servletPath);
//找到当前对应类中要执行哪个方法
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//设置编码
req.setCharacterEncoding("UTF-8");
String operate = req.getParameter("operate");
if (StringUtil.isEmpty(operate)){
operate = "index";
}
//获取当前类中所有的方法集合
Method method = null;
try {
method = controllerBeanObj.getClass().getDeclaredMethod(operate, HttpServletRequest.class, HttpServletResponse.class);
if (method == null){
method.setAccessible(true);
method.invoke(controllerBeanObj,request,response);
}else {
throw new RuntimeException("operate值非法");
}
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
但是现在我们执行程序是跑不起来的,会报空指针异常,因为现在我们的FruitController已经不是一个servlet方法了,已经不会自己去实例化了,所以一定会出问题
经过魔改程序还是执行了(之后还会用一些方法修改回来)
优化业务流程4.0:
为什么之前我们需要魔改呢?
因为我们的FruitController已经不是一个servlet了,用不了thymeleaf渲染数据和页面了,所以魔改之前的页面总是为空,现在要处理的问题就是,怎么把我们的重定向或者渲染或者客户端转发也集成到我们的中央控制器上,也就可以解决我们魔改的问题,也会让框架更加简洁
由于魔改的问题,我们需要一个没有被改动的viewbaseservlet
(最终相当于在3.0最后进行修改,所以现在需要适当还原)
还原后的fruitconntroller:
public class FruitController extends ViewBaseServlet {
FruitDAO fruitDAO = new FruitDAOImpl();
private void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//req.setCharacterEncoding("UTF-8");
String idStr = req.getParameter("id");
Integer id = Integer.parseInt(idStr);
String name = req.getParameter("name");
String priceStr = req.getParameter("price");
Integer price = Integer.parseInt(priceStr);
String countStr = req.getParameter("count");
Integer count = Integer.parseInt(countStr);
String remark = req.getParameter("remark");
Connection connection = null;
try {
connection = JDBCutil.getConnection();
Fruit fruit = new Fruit(id,name,price,count,remark);
fruitDAO.update(connection,fruit);
Fruit fruitAfter = fruitDAO.getFruitByID(connection,id);
//渲染页面跳转(此时index会自动加上.html,到页面去)
//super.processTemplate("index",req,resp);
//服务器转发跳转(直接去页面)
//req.getRequestDispatcher("index.html").forward(req,resp);
//客户端重定向(此时index,是去IndexServlet,完成重新查询后最后用thymeleaf渲染数据和页面)
resp.sendRedirect("fruit.do");
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCutil.closeResource(connection,null);
}
}
private void edit(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String idStr = req.getParameter("id");
if(StringUtil.isNotEmpty(idStr)){
int id = Integer.parseInt(idStr);
Connection connection = null;
try {
connection = JDBCutil.getConnection();
Fruit fruit = fruitDAO.getFruitByID(connection,id);
System.out.println(fruit);
req.setAttribute("fruit",fruit);
super.processTemplate("edit",req,resp);
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCutil.closeResource(connection,null,null);
}
}
}
private void del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String idStr = req.getParameter("id");
if(StringUtil.isNotEmpty(idStr)){
int id = Integer.parseInt(idStr);
System.out.println(id);
Connection connection = null;
try {
connection = JDBCutil.getConnection();
fruitDAO.delFruitByID(connection,id);
resp.sendRedirect("fruit.do");
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCutil.closeResource(connection,null);
}
}
}
private void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//req.setCharacterEncoding("UTF-8");
//String idStr = req.getParameter("id");
//Integer id = Integer.parseInt(idStr);
String name = req.getParameter("name");
String priceStr = req.getParameter("price");
Integer price = Integer.parseInt(priceStr);
String countStr = req.getParameter("count");
Integer count = Integer.parseInt(countStr);
String remark = req.getParameter("remark");
Fruit fruit = new Fruit(0,name,price,count,remark);
Connection connection = null;
try {
connection = JDBCutil.getConnection();
fruitDAO.insert(connection,fruit);
resp.sendRedirect("fruit.do");
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCutil.closeResource(connection,null);
}
}
public void index(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取session
HttpServletRequest request = (HttpServletRequest) req;
HttpSession session = request.getSession();
//此时数据库默认为第一次启动,默认查询第一页
int pageNo = 1;
//此时数据库默认为第一次启动,关键字默认为空
String keyword = null;
//只有每一次点击提交查询按钮才会给oper设置默认值
//获取oper并且判断oper是否为默认值并且不能为空,如果满足,那么这次一定就是查询关键字操作
String oper = req.getParameter("oper");
if(StringUtil.isNotEmpty(oper) && "search".equalsIgnoreCase(oper)){
//点击表单进行第一次查询
//此时设置pageNo为1是为了查询后默认从id低到高进行分页展示
pageNo = 1;
//获取当前session里关键字的值
keyword = req.getParameter("keyword");
//如果关键字为空说明此时用户只是点击了搜素,没加任何关键字,就手动把关键字设置为空字符串
if (StringUtil.isEmpty(keyword)){
keyword = "";
}
//如果关键字不是空,就把它记录到session,让下面的DAO执行查询操作,或者让查询后点击下一页时,也能获取到当前的关键字
session.setAttribute("keyword",keyword);
}else {
//正常查询(也有可能是用户输入了搜素后,点击了下一页上一页操作)
//获取当前session里pageNo的值
String pageNoStr = req.getParameter("pageNo");
//此处是为了计算当前无论哪种情况,都要进行分页查询,判断当前在第几页
//如果前端点击了上一页,就会改变或者新建session里的pageNo的值,判断用户是不是点击了上一页
if(StringUtil.isNotEmpty(pageNoStr)){
//把pageNo转化为int,方便下面DAO使用
pageNo = Integer.parseInt(pageNoStr);
}
//保存当前session里pageNo,方便下一次计算要展示第几条数据
session.setAttribute("pageNo",pageNo);
//获取当前session里关键字的值,看看是不是进行关键字分页查询
Object keywordObj = session.getAttribute("keyword");
if (keywordObj!=null){
//如果关键字不为空,说明此时需要进行关键字分页查询,赋值给keyword,方便下面DAO进行使用
keyword = (String) keywordObj;
}else {
//关键字为空,这是正常的普通查询,但是用户点了下一页,把keyword设置为空,不影响下面DAO的sql语句就可以了
keyword = "";
}
}
FruitDAOImpl fruitDAO = new FruitDAOImpl();
Connection connection = null;
try {
//获取数据库连接
connection = JDBCutil.getConnection();
//获取表中的全部记录
List<Fruit> fruitList = fruitDAO.getByNewPage(connection,keyword,pageNo);
//List<Fruit> fruitList = fruitDAO.getByPage(connection,pageNo);
//输出表中所有的数据
//System.out.println(fruitList);
session.setAttribute("fruitList",fruitList);
//记录条数
int fruitCount = fruitDAO.getNewCount(connection,keyword);
//int fruitCount = fruitDAO.getCount(connection);
//System.out.println("count::"+fruitCount);
//一共有几页
int pageCount = (fruitCount+5-1)/5;
session.setAttribute("pageCount",pageCount);
super.processTemplate("index",req,resp);
} catch (Exception e) {
e.printStackTrace();
}
//关闭数据库连接
JDBCutil.closeResource(connection,null);
}
}
现在想办法把渲染,转发,重定向集成到控制器中
以update方法举例,如果最后不进行服务器转发,而是返回一个字符串,再通过控制器判断字符串当前要干什么,并且做出操作不久可以了吗?
对update返回值进行修改:
控制器接受到update的返回值后进行判断并且重定向操作:
Method method = null;
try {
method = controllerBeanObj.getClass().getDeclaredMethod(operate,HttpServletRequest.class,HttpServletResponse.class);
method.setAccessible(true);
System.out.println(method);
if (method != null){
//接收controller方法执行过后的返回值(默认返回对象)
Object returnObj = method.invoke(controllerBeanObj,req,resp);
//强转为字符串并且进行判断
String methodReturnStr = (String) returnObj;
//判断当前是不是需要重定向操作
if (methodReturnStr.startsWith("redirect:")){
//如果是,进行字符串截取redirect:,只留下看看需要重定向到哪个页面就行
String redirectStr = methodReturnStr.substring("redirect:".length());
//进行重定向
resp.sendRedirect(redirectStr);
}
}else {
throw new RuntimeException("operate值非法");
}
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
所以我们现在的update方法就不需要抛出重定向的异常了
所以现在我们的update代码就是:
private String update(HttpServletRequest req, HttpServletResponse resp) throws ServletException{
//req.setCharacterEncoding("UTF-8");
String idStr = req.getParameter("id");
Integer id = Integer.parseInt(idStr);
String name = req.getParameter("name");
String priceStr = req.getParameter("price");
Integer price = Integer.parseInt(priceStr);
String countStr = req.getParameter("count");
Integer count = Integer.parseInt(countStr);
String remark = req.getParameter("remark");
Connection connection = null;
try {
connection = JDBCutil.getConnection();
Fruit fruit = new Fruit(id,name,price,count,remark);
fruitDAO.update(connection,fruit);
Fruit fruitAfter = fruitDAO.getFruitByID(connection,id);
//渲染页面跳转(此时index会自动加上.html,到页面去)
//super.processTemplate("index",req,resp);
//服务器转发跳转(直接去页面)
//req.getRequestDispatcher("index.html").forward(req,resp);
//客户端重定向(此时index,是去IndexServlet,完成重新查询后最后用thymeleaf渲染数据和页面)
//resp.sendRedirect("fruit.do");
//return给控制器
return "redirect:fruit.do";
} catch (Exception e) {
e.printStackTrace();
return "update:error";
}finally {
JDBCutil.closeResource(connection,null);
//return null;
}
}
对于edit方法的修改:
我们的edit需要进行数据渲染,应该怎么处理?
private String edit(HttpServletRequest req, HttpServletResponse resp) throws ServletException{
String idStr = req.getParameter("id");
if(StringUtil.isNotEmpty(idStr)){
int id = Integer.parseInt(idStr);
Connection connection = null;
try {
connection = JDBCutil.getConnection();
Fruit fruit = fruitDAO.getFruitByID(connection,id);
System.out.println(fruit);
req.setAttribute("fruit",fruit);
//super.processTemplate("edit",req,resp);
return "edit";
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCutil.closeResource(connection,null,null);
}
}
return "edit:error";
}
我们的控制器判断为是不是以redirect:开头,我们把渲染换成不以这玩意开头,控制器价格else就可以了
控制器渲染代码:
为什么无法调用渲染的方法,因为我们的控制器现在只是httpservlet,让控制器继承viewbaseservlet就可以了
对于del方法的修改:
del最后是重定向
private String del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String idStr = req.getParameter("id");
if(StringUtil.isNotEmpty(idStr)){
int id = Integer.parseInt(idStr);
System.out.println(id);
Connection connection = null;
try {
connection = JDBCutil.getConnection();
fruitDAO.delFruitByID(connection,id);
//resp.sendRedirect("fruit.do");
return "redirect:fruit.do";
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCutil.closeResource(connection,null);
}
}
return "del:error";
}
对于add方法的修改:
add最后是重定向
private String add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
String priceStr = req.getParameter("price");
Integer price = Integer.parseInt(priceStr);
String countStr = req.getParameter("count");
Integer count = Integer.parseInt(countStr);
String remark = req.getParameter("remark");
Fruit fruit = new Fruit(0,name,price,count,remark);
Connection connection = null;
try {
connection = JDBCutil.getConnection();
fruitDAO.insert(connection,fruit);
//resp.sendRedirect("fruit.do");
return "redirect:fruit.do";
} catch (Exception e) {
e.printStackTrace();
return "add:error";
}finally {
JDBCutil.closeResource(connection,null);
}
}
对于index方法的修改:
index最后是数据渲染
现在我们发现,我们的fruitController里已经没有需要resq(转发)的东西了,控制器帮我们做了,所以传参数的时候resq就可以不用了,删除,而且现在fruitController也不用继承viewbaseservlet了
记得修改控制器的传参个数
测试:功能正常
优化业务流程5.0:
都到现在这种程度了,还有哪里需要优化吗?
我们发现现在的fruitController里的方法基本上里面都需要通过req获取参数,这一点控制器可不可以帮助我们完成,这样子我们的fruitController就已经变成一个普通的类了
怎么传?:改写方法参数类型就可以穿
传哪几个?:这才是问题的重点
对于update方法进行修改:
对于edit方法进行修改:
原本的:
我们的传参个数一定要改
下面原本获取的判断id是否为空还有强制转换就可以直接改成id!=null了 ,因为我们传进来的就应该是int类型
因为我们要向作用域里存数据,所以还是需要传入req的
修改后:
对于del方法进行修改:
对于add方法进行修改:
对于index方法进行修改:
因为我们要向作用域里存数据,所以还是需要传入req的
原本需要获取oper看当前是普通查询还是表单提交,需要传入(在控制器获取)
原本需要获取keyword搜索框里的关键字信息,需要传入(在控制器获取)
原本需要获取pageNo记录当前查询的是第几页,需要传入(在控制器获取)
我们现在所有的强制转换和判断为空操作都可以去掉了
现在我们fruitcontroller里的方法就非常的简洁方便了,主要是如何在控制器里获取参数
在控制器中获取并且处理参数:
我们可以用method.getparameters获取当前方法的参数数组这个思路来实现
注意:由于我们已经更改了传入参数的类型和数量,所以我们之前反射调用方法的语句已经不适用了
我们正好也要看每个方法的参数都有哪些,所以可以设计一个for循环,获取每一个方法,如果和operate对应,就获取相应参数,并且执行方法
经过测试我们发现method.getparameters获取的方法名称都是arg0.....3,但是方法是找对了,如果我们能获取实际的方法名,直接req.setAtru(“实际方法名”),就可以获取我们想要的参数了,有没有方法?
有的,通过idea设置
现在我们获取的就是实际的参数名称了
设置结束后记得重新编译一下
现在就已经成功的获取了真实参数名了
我们通过for循环和定义一个和parameters等长的对象数组来实现把我们需要的数值都插入到对象数组中
在下面invoke直接传入parameterValues就可以了
但是现在会有两个问题
问题一:第一次调用方法时,默认调用index方法,此时index方法pageNo是null,但是默认情况下pageNo应该为1,所以需要加
问题二:后几次调用的时候,我们的pageNo应该是integar,但是我们传入数据的时候,默认是String,我们可以通过parameter.gettype().getname()来获取当前真正的类名,如果类名为integar,就强转,通过中间变量给parameterValues,就可以了
测试:一切功能正常,现在Controller的代码就很简洁,而且控制器代码很通用,非常不错
总结: