反射时竟然NoSuchMethodException了!看这篇超详细的解决方案吧

news2025/2/27 20:52:53

前几天九哥在讲Servlet时,为了灵活地使用同一个Servlet来处理对同一张表的业务操作请求,我给学生讲解了BaseServlet工具类的封装,基本实现思路有如下几个步骤。

一. 反射封装BaseServlet工具类

使用反射封装BaseServlet工具类,无论是哪个Servlet接收到请求,都由该类完成请求分发。因此该类的主要作用就是通过反射机制,确定我们请求的到底是哪个Servlet的哪个方法。

/*
 * BaseServlet 获取客户端请求的是哪个servlet的哪个方法
 * */
public class BaseServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取客户端发来请求的标识:即要执行的方法名
        String method = req.getParameter("method");
        //获取方法属于哪个Servlet类
        Class<? extends BaseServlet> clazz = this.getClass();
        //通过类字节码对象获取要执行方法的对象
        try {
            Method mh = clazz.getMethod(method, HttpServletRequest.class, HttpServletResponse.class);
            //执行方法
            mh.invoke(this,req,resp); // this.insert(req,resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

二. 继承BaseServlet父类

以后再创建Servlet时,我们要使任意一个Servlet类,不再直接继承HttpServlet,而是要继承统一的BaseServlet,完成请求的分发管理,例如:

@WebServlet("/stuinfo")
public class StuinfoServlet extends BaseServlet {
    //删除方法
    public void delById(HttpServletRequest req, HttpServletResponse resp) {

    }

    //修改学员信息
    public void update(HttpServletRequest req, HttpServletResponse resp){

    }

    //根据学号查询方法
    public void findById(HttpServletRequest req, HttpServletResponse resp)  {
    }

    //查询全部方法
    public void findAll(HttpServletRequest req, HttpServletResponse resp)  {
    }

    //添加方法
    public void insert(HttpServletRequest req, HttpServletResponse resp)  {
    }
}

三. 异常展现

然而有个别同学在按照上述思路自己编写代码时,却遇到了下面的NoSuchMethodException异常。他排查许久未果,于是就来找九哥帮他解决。

四. 异常原因

起初,九哥以为是学生从客户端发出请求时,未携带执行方法的标识或携带的方法标识与实际方法名不匹配,从而导致通过反射机制获取方法对象时报错。因为我们知道,在通过Methodmh=clazz.getMethod(method,HttpServletRequest.class,HttpServletResponse.class)获取Method对象时,必须保证方法名、参数匹配,才能找到指定的方法,否则就会出现此类异常。

但经过排查,发现并不是以上原因,该学生的代码如下:

@WebServlet("/stuinfo")
public class StuinfoServlet extends BaseServlet {
    //创建serivce层对象
    private StuinfoService ss = new StuinfoSerivceImpl();
    
    //查询方法
    private void findAll(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //调用service层查询方法
        List<Stuinfo> list = ss.findAll();
        //将list集合数据保存到域对象中
        req.setAttribute("stuList",list);
        //跳转到主页面
        req.getRequestDispatcher("index.jsp").forward(req,resp);
    }
}

五. 异常解决

可能你也一眼就看到了,上述代码中,查询方法使用的是private修饰符,而私有成员在该类的外部是不能被访问的!因此我们在利用反射,通过getMethod()方法获取Method对象时就会出现NoSuchMethodException异常。所以现在的解决办法,你是不是立刻就明朗了,我们直接将private改成public就可以了

六. 暴力反射

上面的问题是解决了,但大家还要知道,反射机制中还有一种叫暴力反射,听起来是不是很厉害!!利用暴力反射,即使被private修饰也可以进行正常的操作。

九哥在这里给大家再补上一刀,反射里的Constructor、Field、Method三个类都有getDeclaredXxx方法(这里的Xxx表示Constructor、Field、Method),该方法可以不受权限控制,就能够获取到类中的这些成员信息。如果我们想要使用私有的构造函数、字段、方法,则会自动访问类的isAccessable,其默认值是false,表示在访问成员时需要安全检查,如果发现是私有的则不允许访问。所以,如果我们想要访问类中的私有成员时,需要调用setAccessible(boolean flag)方法,将其改为true。这样,我们就可以对类中的私有成员进行操作了。

 *威哥Java学习交流Q群:691533824
加群备注:CSDN推荐
      

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/407719.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uview常用组件案例操作及详解(一) 选择器 picker

uview常用组件案例操作及详解&#xff08;一&#xff09; 选择器 picker 1.图片示例 2.使用方法 *为简便代码不提供样式 <view><view><text>行业性质</text><text>*</text></view><view><text v-if"!text.industry…

echarts中的legend属性

legend: {orient: "vertical",right: "0%",top: "15%",icon: "circle", //小圆点itemWidth: 8,itemHeight: 8,itemGap: 15, //间隔formatter: function (params) {let tip1 "";let tip "";let le params.leng…

【uni-app】swiper的使用

最近在学习小程序的开发&#xff0c;其中有用到swiper&#xff0c;在这里记录一下我的学习历程 有一些人&#xff0c;他刚开始并不会开发小程序&#xff0c;但是在任务面前&#xff0c;没有什么是不可以学的… 刚开始接触到swiper的时候&#xff0c;是在uni-app的官方文档里&am…

Vue中的Pinia状态管理工具 | 一篇文章教会你全部使用细节

文章目录Pinia状态管理Pinia和Vuex的对比Pinia基本使用&#x1f364;创建Pinia&#x1f364;创建StorePinia核心概念State&#x1f35f;state基本使用&#x1f35f;state其他操作Pinia核心Getters&#x1f355;getters基本使用&#x1f355;getters其他操作Pinia核心Actions&am…

React -- useState 的使用及注意事项

一、基本使用 useState是 react 提供的一个定义响应式变量的 hook 函数&#xff0c;基本语法如下&#xff1a; const [count, setCount] useState(initialCount)它返回一个状态和一个修改状态的方法&#xff0c;状态需要通过这个方法来进行修改&#xff1b;initialCount 是我…

Vue3+Vite实现动态路由

项目基本目录 1.首先定义初始默认的路由routes(router.js文件),vue文件使用import引入可以按需加载 import {createRouter,createWebHashHistory } from "vue-router";import store from ../store/index.jsconst routes [{path: "/login",component: () …

jsjiami.com V6版本,js解密的方法。

我们在爬内容&#xff0c;抓取页面的时候&#xff0c;总会遇到sojson v5&#xff0c;jsjiami.com的v6加密。 jsjiami v6 &#xff1a; JS加密,JS不可逆加密,JS混淆,JS混淆加密,JS压缩加密 - [JavaScript加密] 我看了下这个js完全有效。废话不多说。直接上代码。 (function (…

vue中深度选择器

scoped的作用 scoped 可以使当前的样式只在自己当前的组件内起作用。为了防止在一个组件内引入了子组件&#xff0c;而子组件没有加scoped。这个时候如果父子组件有相同的类名&#xff0c;就会产生样式的影响。 原理: 加了scoped就相当于给当前组件所有的标签添加一个【data-v-…

微信小程序实现轮播图

实现轮播图之前必须知道以下三点&#xff1a; 一、轮播图外层容器swiper 二、每一个轮播项swiper-item 三、swiper标签存在默认样式 1. width 100% 2. height 默认为 150px 3 .swiper高度无法实现由内容撑开 默认的150px高度的轮播图如下图: 原图是长这个样子的&#xf…

bootstrap-fileinput(二:编辑(修改)界面文件的上传,回显,删除(数据库同时删除)的操作 )

文章目录bootstrap-fileinput(二&#xff1a;编辑(修改)界面文件的上传&#xff0c;回显&#xff0c;删除(数据库同时删除)的操作 )一、编辑界面文件的上传二、编辑界面文件的回显1.文件的实体类&#xff1a;2.想要回显文件&#xff0c;首先要在工程类(你的编辑界面的主类)里面…

ES6面试问题汇总

面试官通过总问题&#xff0c;ES6方法开始提问 1.ES6有哪些新增方法&#xff1f;/你了解哪些ES6方法&#xff1f;&#xff08;总问题&#xff09; 块级作用域、 模板字符串、 解构赋值、 箭头函数、 函数默认参数、 剩余参数&运算符、 set和map、 import和exprot用…

Vue中实现过渡动画

文章目录Vue的transition动画Transition动画的使用Transition组件的原理Transition动画的classVue的animation动画Animation动画的使用同时设置两种动画(了解)过渡的模式mode列表过渡列表过渡的介绍列表过渡的使用Vue的transition动画 Transition动画的使用 在开发中&#xf…

vite配置cdn优化打包体积

文章目录前言一、版本确认二、使用步骤1.rollup-plugin-visualizer打包体积可视化面板2.配置cdn方法第一种方法&#xff1a; vite-plugin-cdn-import第二种方法&#xff1a; rollup-plugin-external-globals总结前言 大家都知道前端性能优化的方法&#xff0c;cdn外部引入的方…

【微信小程序】小程序知识补充篇

&#x1f381;写在前面&#xff1a; 观众老爷们好呀&#xff0c;这里是前端小刘不怕牛牛频道&#xff0c;小程序系列又更新了呀。 还有就是中秋节就快来啦&#xff0c;程序员过中秋&#xff0c;当然是要好好放松一下啦&#xff0c;那么中秋前我们就不能偷懒了&#xff0c;赶紧学…

Controller层接收前端传参的几种方法。@RequestParam、@RequestBody、@PathVariable。及参数校验。

一、RequestParam 主要用于将请求参数区域的数据映射到控制层方法的参数上 // http://localhost:8080/wh/user/edit?Id9452659856325148452&name天天向上// RequestParam源码Target({ElementType.PARAMETER}) // 只能作用于参数上 Retention(RetentionPolicy.RUNTIME) D…

vue watch监听数据解决新旧值一样的问题(newValue, oldValue)

watch是监听 Vue 实例变化的一个表达式或方法。回调函数得到的参数为新值和旧值。 基础用法 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge…

异步函数async

什么是同步异步 在最新的ES7&#xff08;ES2017&#xff09;中提出的前端异步特性&#xff1a;async、await。 在了解async和await之前得先明白什么是同步函数&#xff0c;什么是异步函数。 同步函数&#xff1a;当一个函数是同步执行时&#xff0c;那么当该函数被调用时不会…

前端CryptoJS和Java后端数据互相加解密(AES)

目录一、序言二、关于前端CryptoJS1、CryptoJS简单介绍2、加密和填充模式选择3、前端AES加解密示例(1) cryptoutils工具类(2) 测试用例(3) 加解密后输出内容说明三、Java后端AES加解密1、Java中支持的加密模式和填充说明2、工具类CryptoUtils3、测试用例一、序言 最近刚好在做…

nodejs——解决跨域问题

目录 1什么是跨域 2解决 1 jsonp(缺点&#xff1a;不能请求post请求&#xff09; 1 index.html页 2 proxy.js页面 搭建一个服务器&#xff08;写好代码后&#xff0c;在cmd上启动&#xff09; 3效果 2服务端代理 &#xff08;由于后端请求不受浏览器同源策略影响&…

Bootstrap、栅格系统布局

一、Bootstrap Bootstrap是一个基于HTML、CSS和JavaScript语言编写的框架&#xff0c;具有简单、灵活的特性&#xff0c;拥有样式库、组件和插件。 Bootstrap常用来开发响应式布局和移动设备优先的Web项目&#xff0c;能够帮助开发者快速搭建前端页面。Bootstrap官方网站:Boot…