当前位置: 首页 > news >正文

网站规划设计的步骤注册安全工程师含金量

网站规划设计的步骤,注册安全工程师含金量,云南高端网站建设,zedu小语种网站建设文章目录 1. 如何自定义插件1.1 创建接口Interceptor的实现类1.2 配置拦截器1.3 运行程序 2. 插件原理2.1 解析过程2.2 创建代理对象2.2.1 Executor2.2.2 StatementHandler2.2. 3ParameterHandler2.2.4 ResultSetHandler 2.3 执行流程2.4 多拦截器的执行顺序 3. PageHelper3.1 … 文章目录 1. 如何自定义插件1.1 创建接口Interceptor的实现类1.2 配置拦截器1.3 运行程序 2. 插件原理2.1 解析过程2.2 创建代理对象2.2.1 Executor2.2.2 StatementHandler2.2. 3ParameterHandler2.2.4 ResultSetHandler 2.3 执行流程2.4 多拦截器的执行顺序 3. PageHelper3.1 配置和代码3.2 原理解析 4. 拦截器应用场景 1. 如何自定义插件 1.1 创建接口Interceptor的实现类 /*** author Clinton Begin*/ public interface Interceptor {// 执行拦截逻辑的方法Object intercept(Invocation invocation) throws Throwable;// 决定是否触发 intercept()方法default Object plugin(Object target) {return Plugin.wrap(target, this);}// 根据配置 初始化 Intercept 对象default void setProperties(Properties properties) {// NOP}} mybatis运行拦截的内容包括 Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)ParameterHandler (getParameterObject, setParameters)ResultSetHandler (handleResultSets, handleOutputParameters)StatementHandler (prepare, parameterize, batch, update, query) 定义一个实现类。 /*** MyBatis中的自定义的拦截器** Signature 表示一个方法签名唯一确定一个方法*/ Intercepts({Signature(type Executor.class, // 拦截类型method query, // 拦截方法// args 中指定 被拦截方法的 参数列表args {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),Signature(type Executor.class,method close,args {boolean.class})}) public class MyInterceptor implements Interceptor {private String interceptorName;public String getInterceptorName() {return interceptorName;}/*** 执行拦截的方法*/Overridepublic Object intercept(Invocation invocation) throws Throwable {System.out.println(------MyInterceptor before---------);Object proceed invocation.proceed();System.out.println(------MyInterceptor after---------);return proceed;}Overridepublic Object plugin(Object target) {return Interceptor.super.plugin(target);}Overridepublic void setProperties(Properties properties) {System.out.println(setProperties : properties.getProperty(interceptorName));this.interceptorName properties.getProperty(interceptorName);} } 1.2 配置拦截器 pluginsplugin interceptorcom.boge.interceptor.MyInterceptorproperty nameinterceptorName valuemyInterceptor//plugin/plugins1.3 运行程序 Testpublic void test2() throws Exception{// 1.获取配置文件InputStream in Resources.getResourceAsStream(mybatis-config.xml);// 2.加载解析配置文件并获取SqlSessionFactory对象SqlSessionFactory factory new SqlSessionFactoryBuilder().build(in);// 3.根据SqlSessionFactory对象获取SqlSession对象SqlSession sqlSession factory.openSession();// 4.通过SqlSession中提供的 API方法来操作数据库UserMapper mapper sqlSession.getMapper(UserMapper.class);Integer param 1;User user mapper.selectUserById(param);System.out.println(user); }拦截的query方法和close方法的源码位置在如下 2. 插件原理 2.1 解析过程 解析全局配置文件过程中查看XMLConfigBuilder类的方法parseConfiguration。 private void pluginElement(XNode parent) throws Exception {if (parent ! null) {for (XNode child : parent.getChildren()) {// 获取plugin 节点的 interceptor 属性的值String interceptor child.getStringAttribute(interceptor);// 获取plugin 下的所有的properties子节点Properties properties child.getChildrenAsProperties();// 获取 Interceptor 对象Interceptor interceptorInstance (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance();// 设置 interceptor的 属性interceptorInstance.setProperties(properties);// Configuration中记录 Interceptorconfiguration.addInterceptor(interceptorInstance);}}}该方法主要创建Interceptor 对象并设置属性最终放在configuration对象的InterceptorChain里面 来看InterceptorChain的源码。 /*** InterceptorChain 记录所有的拦截器* author Clinton Begin*/ public class InterceptorChain {// 保存所有的 Interceptor 也就我所有的插件是保存在 Interceptors 这个List集合中的private final ListInterceptor interceptors new ArrayList();// 现在我们定义的有一个 Interceptor MyInterceptorpublic Object pluginAll(Object target) {for (Interceptor interceptor : interceptors) { // 获取拦截器链中的所有拦截器target interceptor.plugin(target); // 创建对应的拦截器的代理对象}return target;}public void addInterceptor(Interceptor interceptor) {interceptors.add(interceptor);}public ListInterceptor getInterceptors() {return Collections.unmodifiableList(interceptors);}} 可以看到拦截器放在这个list变量interceptors 。 2.2 创建代理对象 2.1步骤创建了拦截器并且保存在InterceptorChain**那拦截器如何与目标对象关联**拦截器拦截对象包括Executor,ParameterHandler,ResultSetHandler,StatementHandler. 这些对象创建的时候需要注意什么 2.2.1 Executor 在创建SqlSession的过程中会创建执行器Executor。可以看到Executor植入插件 public Executor newExecutor(Transaction transaction, ExecutorType executorType) {// 获取执行器的类型executorType executorType null ? defaultExecutorType : executorType;executorType executorType null ? ExecutorType.SIMPLE : executorType;Executor executor;// 根据对应的类型创建执行器if (ExecutorType.BATCH executorType) {executor new BatchExecutor(this, transaction);} else if (ExecutorType.REUSE executorType) { // 针对 Statement 对象做缓存executor new ReuseExecutor(this, transaction);} else {// 默认 SimpleExecutor 每一次只是SQL操作都创建一个新的Statement对象executor new SimpleExecutor(this, transaction);}// 二级缓存开关settings 中的 cacheEnabled 默认是 true// 映射文件中 cache 标签 -- 创建 Cache对象// settings 中的 cacheEnabled true 真正的对 Executor 做了缓存的增强if (cacheEnabled) {// 穿衣服的事情 -- 装饰器模式executor new CachingExecutor(executor);}// 植入插件的逻辑至此四大对象已经全部拦截完毕executor (Executor) interceptorChain.pluginAll(executor);return executor;}进入pluginAll方法 // 现在我们定义的有一个 Interceptor MyInterceptorpublic Object pluginAll(Object target) {for (Interceptor interceptor : interceptors) { // 获取拦截器链中的所有拦截器target interceptor.plugin(target); // 创建对应的拦截器的代理对象}return target;}再进入plugin方法 再查看Plugin工具类的实现 wrap方法。 /*** 创建目标对象的代理对象* 目标对象 Executor ParameterHandler ResultSetHandler StatementHandler* param target 目标对象* param interceptor 拦截器* return*/public static Object wrap(Object target, Interceptor interceptor) {// 获取用户自定义 Interceptor中Signature注解的信息// getSignatureMap 负责处理Signature 注解 interceptor 自定义的拦截器MapClass?, SetMethod signatureMap getSignatureMap(interceptor);// 获取目标类型Class? type target.getClass();// 获取目标类型 实现的所有的接口Class?[] interfaces getAllInterfaces(type, signatureMap);// 如果目标类型有实现的接口 就创建代理对象if (interfaces.length 0) {return Proxy.newProxyInstance(type.getClassLoader(),interfaces,new Plugin(target, interceptor, signatureMap));}// 否则原封不动的返回目标对象return target;}getSignatureMap方法 再来看Plugin的源码。 /*** author Clinton Begin*/ public class Plugin implements InvocationHandler {private final Object target; // 目标对象private final Interceptor interceptor; // 拦截器private final MapClass?, SetMethod signatureMap; // 记录 Signature 注解的信息private Plugin(Object target, Interceptor interceptor, MapClass?, SetMethod signatureMap) {this.target target;this.interceptor interceptor;this.signatureMap signatureMap;}/*** 创建目标对象的代理对象* 目标对象 Executor ParameterHandler ResultSetHandler StatementHandler* param target 目标对象* param interceptor 拦截器* return*/public static Object wrap(Object target, Interceptor interceptor) {// 获取用户自定义 Interceptor中Signature注解的信息// getSignatureMap 负责处理Signature 注解 interceptor 自定义的拦截器MapClass?, SetMethod signatureMap getSignatureMap(interceptor);// 获取目标类型Class? type target.getClass();// 获取目标类型 实现的所有的接口Class?[] interfaces getAllInterfaces(type, signatureMap);// 如果目标类型有实现的接口 就创建代理对象if (interfaces.length 0) {return Proxy.newProxyInstance(type.getClassLoader(),interfaces,new Plugin(target, interceptor, signatureMap));}// 否则原封不动的返回目标对象return target;}/*** 代理对象方法被调用时执行的代码* param proxy* param method* param args* return* throws Throwable*/Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {// 获取当前方法所在类或接口中可被当前Interceptor拦截的方法 Executor querySetMethod methods signatureMap.get(method.getDeclaringClass());if (methods ! null methods.contains(method)) {// 当前调用的方法需要被拦截 执行拦截操作return interceptor.intercept(new Invocation(target, method, args));}// 不需要拦截 则调用 目标对象中的方法return method.invoke(target, args);} catch (Exception e) {throw ExceptionUtil.unwrapThrowable(e);}}/*** 获取拦截器中的 Intercepts 注解中的相关内容* param interceptor* return*/private static MapClass?, SetMethod getSignatureMap(Interceptor interceptor) {// 获取 Intercepts 注解Intercepts interceptsAnnotation interceptor.getClass().getAnnotation(Intercepts.class);// issue #251if (interceptsAnnotation null) {throw new PluginException(No Intercepts annotation was found in interceptor interceptor.getClass().getName());}// 获取 Signature 注解中的内Signature[] sigs interceptsAnnotation.value();MapClass?, SetMethod signatureMap new HashMap();for (Signature sig : sigs) {SetMethod methods signatureMap.computeIfAbsent(sig.type(), k - new HashSet());try {Method method sig.type().getMethod(sig.method(), sig.args());methods.add(method);} catch (NoSuchMethodException e) {throw new PluginException(Could not find method on sig.type() named sig.method() . Cause: e, e);}}return signatureMap;}private static Class?[] getAllInterfaces(Class? type, MapClass?, SetMethod signatureMap) {SetClass? interfaces new HashSet();while (type ! null) {for (Class? c : type.getInterfaces()) {// 判断 目标对象的 接口类型是否在 Signature 注解中声明的有if (signatureMap.containsKey(c)) {interfaces.add(c);}}// 继续获取父类type type.getSuperclass();}return interfaces.toArray(new Class?[interfaces.size()]);}} 2.2.2 StatementHandler 2.2. 3ParameterHandler 2.2.4 ResultSetHandler 2.3 执行流程 以Executor的query方法为例实际执行的是代理对象。 然后会执行Plugin的invoke方法。 然后进入interceptor.intercept进入自定义拦截器 2.4 多拦截器的执行顺序 总结 对象作用Interceptor自定义插件需要实现接口实现4个方法InterceptChain配置的插件解析后会保存在Configuration的InterceptChain中Plugin触发管理类还可以用来创建代理对象Invocation对被代理类进行包装可以调用proceed()调用到被拦截的方法 3. PageHelper 3.1 配置和代码 dependencygroupIdcom.github.pagehelper/groupIdartifactIdpagehelper/artifactIdversion4.1.6/version /dependency!-- com.github.pagehelper为PageHelper类所在包名 -- plugin interceptorcom.github.pagehelper.PageHelperproperty namedialect valuemysql /!-- 该参数默认为false --!-- 设置为true时会将RowBounds第一个参数offset当成pageNum页码使用 --!-- 和startPage中的pageNum效果一样 --property nameoffsetAsPageNum valuetrue /!-- 该参数默认为false --!-- 设置为true时使用RowBounds分页会进行count查询 --property namerowBoundsWithCount valuetrue /!-- 设置为true时如果pageSize0或者RowBounds.limit 0就会查询出全部的结果 --!-- 相当于没有执行分页查询但是返回结果仍然是Page类型 --property namepageSizeZero valuetrue /!-- 3.3.0版本可用 - 分页参数合理化默认false禁用 --!-- 启用合理化时如果pageNum1会查询第一页如果pageNumpages会查询最后一页 --!-- 禁用合理化时如果pageNum1或pageNumpages会返回空数据 --property namereasonable valuefalse /!-- 3.5.0版本可用 - 为了支持startPage(Object params)方法 --!-- 增加了一个params参数来配置参数映射用于从Map或ServletRequest中取值 --!-- 可以配置pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值 --!-- 不理解该含义的前提下不要随便复制该配置 --property nameparams valuepageNumstart;pageSizelimit; /!-- always总是返回PageInfo类型,check检查返回类型是否为PageInfo,none返回Page --property namereturnPageInfo valuecheck / /plugin代码 Testpublic void test5() throws Exception{// 1.获取配置文件InputStream in Resources.getResourceAsStream(mybatis-config.xml);// 2.加载解析配置文件并获取SqlSessionFactory对象SqlSessionFactory factory new SqlSessionFactoryBuilder().build(in);// 3.根据SqlSessionFactory对象获取SqlSession对象SqlSession sqlSession factory.openSession();// 4.通过SqlSession中提供的 API方法来操作数据库UserMapper mapper sqlSession.getMapper(UserMapper.class);// 分页PageHelper.startPage(1, 10);ListUser users mapper.selectUserList();System.out.println(users);// 5.关闭会话sqlSession.close();}执行结果 3.2 原理解析 PageHelper实现了Interceptor接口拦截接口Executor的query方法。也就是说SqlSession的executor创建之后经过类Plugin的wrap方法处理之后变成代理对象。 接下里的 PageHelper.startPage(1, 10)做了什么 Let’s get into it. F7跟踪到这里 这里主要设置页码和分页大小。SqlUtil类来面有个TreadLocal变量LOCAL_PAGE绑定当前线程的page对象。 接着往下走 接着到PageHelper的intercept(Invocation invocation)方法 最终在doProcessPage方法里面实现分页查询。 /*** Mybatis拦截器方法** param invocation 拦截器入参* return 返回执行结果* throws Throwable 抛出异常*/private Page doProcessPage(Invocation invocation, Page page, Object[] args) throws Throwable {//保存RowBounds状态RowBounds rowBounds (RowBounds) args[2];//获取原始的msMappedStatement ms (MappedStatement) args[0];//判断并处理为PageSqlSourceif (!isPageSqlSource(ms)) {processMappedStatement(ms);}//设置当前的parser后面每次使用前都会setThreadLocal的值不会产生不良影响((PageSqlSource)ms.getSqlSource()).setParser(parser);try {//忽略RowBounds-否则会进行Mybatis自带的内存分页args[2] RowBounds.DEFAULT;//如果只进行排序 或 pageSizeZero的判断if (isQueryOnly(page)) {return doQueryOnly(page, invocation);}//简单的通过total的值来判断是否进行count查询if (page.isCount()) {page.setCountSignal(Boolean.TRUE);//替换MSargs[0] msCountMap.get(ms.getId());//查询总数Object result invocation.proceed();//还原msargs[0] ms;//设置总数page.setTotal((Integer) ((List) result).get(0));if (page.getTotal() 0) {return page;}} else {page.setTotal(-1l);}//pageSize0的时候执行分页查询pageSize0的时候不执行相当于可能只返回了一个countif (page.getPageSize() 0 ((rowBounds RowBounds.DEFAULT page.getPageNum() 0)|| rowBounds ! RowBounds.DEFAULT)) {//将参数中的MappedStatement替换为新的qspage.setCountSignal(null);BoundSql boundSql ms.getBoundSql(args[1]);args[1] parser.setPageParameter(ms, args[1], boundSql, page);page.setCountSignal(Boolean.FALSE);//执行分页查询Object result invocation.proceed();//得到处理结果page.addAll((List) result);}} finally {((PageSqlSource)ms.getSqlSource()).removeParser();}//返回结果return page;}// todo 待仔细研究 4. 拦截器应用场景 作用描述实现方式水平分表一张费用表按月度拆分为12张表。fee_202001-202012。当查询条件出现月度tran_month时把select语句中的逻辑表名修改为对应的月份表。对query update方法进行拦截在接口上添加注解通过反射获取接口注解根据注解上配置的参数进行分表修改原SQL例如id取模按月分表数据脱敏手机号和身份证在数据库完整存储。但是返回给用户屏蔽手机号的中间四位。屏蔽身份证号中的出生日期。query——对结果集脱敏菜单权限控制不同的用户登录查询菜单权限表时获得不同的结果在前端展示不同的菜单对query方法进行拦截在方法上添加注解根据权限配置以及用户登录信息在SQL上加上权限过滤条件黑白名单有些SQL语句在生产环境中是不允许执行的比如like %%对Executor的update和query方法进行拦截将拦截的SQL语句和黑白名单进行比较控制SQL语句的执行全局唯一ID在高并发的环境下传统的生成ID的方式不太适用这时我们就需要考虑其他方式了创建插件拦截Executor的insert方法通过UUID或者雪花算法来生成ID并修改SQL中的插入信息
http://wiki.neutronadmin.com/news/267567/

相关文章:

  • 河南城乡建设网站网站建设方案策划书前言
  • python适合大型网站开发吗wordpress传输失败
  • 网站建设的总结少女免费观看完整电视电影
  • 广州做护肤品的网站河南省人事考试网
  • 网站开发需要提供哪些东西东阿聊城做网站的公司
  • 大连哪家网站做的好南山区
  • 贸易公司网站制作做心理咨询可以在哪些网站发贴
  • 网站建设预付款如何付wordpress 判断用户
  • 网站排名软件包年做网站简单
  • 网站建设费用做无形资产怎么做饲料电商网站
  • 上海广告公司招聘信息网站页面优化方法
  • 中国建筑集团网站建设企业网站步骤
  • 花市小说网站那里进网站主题包括
  • 微网站开发协议html简单网页代码课程表
  • 淮安网站建设工作室网站开发哪一种语言好
  • 石家庄免费网站设计网店代运营哪个好
  • 用ps怎么做网站网站开发公司需要那些硬件设备
  • 网站开发网页权限如何控制青海住房建设网站
  • 票务网站做酒店推荐的目的网站开发栏目需求1
  • 莒县网站制作wordpress忘记密码如何重新安装
  • 网站开发工程师工作描述wordpress 登录跳转
  • 龙岗开发公司网站建设wordpress编辑器分页
  • 深圳品牌营销型网站建设网站后台怎么修改代码
  • 能添加网站的导航有创意的网站开发
  • 中国建设银行网站-诚聘英才双流县规划建设局网站
  • p2p免费网站建设wordpress的标题字怎么变
  • 电子商务网站建设目标定制软件开发软件
  • 找兼职做网站的哪里找flask 网站开发
  • 收费图片网站网站推广工具有哪些
  • 站长百度国外域名网站