- 浏览: 408965 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (347)
- java基础 (58)
- ajax (10)
- s2sh (10)
- 版本控制 (4)
- 数据库 (34)
- 服务器 (4)
- 开发工具 (8)
- javascript (15)
- soockte (5)
- ext (2)
- 环境搭建 (7)
- struts2 (9)
- 找工作中的面试技巧 (2)
- 承接网站零活 (0)
- JNI+JONSE+OGNL (8)
- 性能优化 (4)
- Android开发 (5)
- xul (8)
- jquery (2)
- 线程 (3)
- jsp+jdbc (7)
- servlet (2)
- java对xml操作 (1)
- IO流的操作 (10)
- 项目开发前配置 (1)
- css (0)
- 上传、下载 (2)
- 知识探讨 (2)
- html (2)
- HQL (0)
- 工作技巧 (1)
- IT (1)
- Hibernate杂谈 (10)
- Spring杂谈 (35)
- DWR (5)
- JUnit测试 (3)
- EasyMock测试web (1)
- ibatis (6)
- maysql (5)
- C++ (0)
- 正则表达式(解剖) (1)
- 密码安全 (2)
- 上传 (1)
- socket (1)
- jni(java与c++结合) (1)
- jdk版本问题 (0)
- tomcat版本问题 (5)
- linux基本命令(初学) (7)
- linux项目发布 (1)
- 3年的经验总结 (1)
- 加解密 (2)
- 高级java阶段 (2)
- java内存分区 (1)
- 浏览器 (1)
- 职业规划 (1)
- 管理 (5)
- java语音 (1)
- SSH (1)
- jsp (3)
- extjs (1)
- uml (2)
- 加密 (1)
- web (2)
- Ant (1)
- 自述 (1)
- Linux (1)
- ssh源码解剖 (1)
- 代码优化 (1)
- 设计模式 (0)
- xml (2)
- JOSN (1)
- scala (0)
- hadoop (0)
- spark (0)
- hana (1)
- shior (1)
- java Word (6)
- java PDF (4)
- java Excel (0)
最新评论
-
高级java工程师:
ztao2333 写道谢谢。收藏下这个总结。呵呵
温习jdk和tomcat -
ztao2333:
大写的,不是大学的
温习jdk和tomcat -
ztao2333:
谢谢。收藏下这个总结。
温习jdk和tomcat -
the_small_base_:
你好,可以提供调用方法吗?需要的Jar,能发下源码吗?谢谢
java实现语音 -
高级java工程师:
文思涌动 写道楼主新年好。可否再传一遍给我,我没有收到, 不清 ...
s2sh整合
使用springboot的人基本都知道swagger,那么swagger是如何生成swagger-ui.html页面的呢?相信大家都能猜到,就是扫描程序中带有指定注解的类(带有@RestController和 @Controller)和方法(@RequestMapping等),然后又根据方法上的@ApiOperation和@ApiImplicitParams去生成页面上要显示的一些元素。
实际项目中我们也会有类似需求,例如权限校验,我们需要先扫描程序中有哪些接口(就是找有哪些类有@RestController注解),然后在根据自定义的一些注解,扫描是否这些controller的方法需要配置权限校验。那么如何来实现?
第一步,
根据basePackage,开始遍历所有的类,然后测试该类是否添加了@RestController注解。
需要注意的是,当我们的类是在jar文件中时,不需要递归,但是在普通的文件中(目录存放文件)需要递归循环。
第二步
根据第一步提供的controller,遍历该类的所有方法,检查该方法是否添加MyChecker注解(MyChecker为自定义的注解)
效果截图
http://dl2.iteye.com/upload/attachment/0132/0836/2c30583b-ee70-368b-b4b7-3cb38e5b1dba.png
实际项目中我们也会有类似需求,例如权限校验,我们需要先扫描程序中有哪些接口(就是找有哪些类有@RestController注解),然后在根据自定义的一些注解,扫描是否这些controller的方法需要配置权限校验。那么如何来实现?
第一步,
根据basePackage,开始遍历所有的类,然后测试该类是否添加了@RestController注解。
需要注意的是,当我们的类是在jar文件中时,不需要递归,但是在普通的文件中(目录存放文件)需要递归循环。
private List<Class<?>> getClassesWithAnnotationFromPackage(String packageName, Class<? extends Annotation> annotation) { List<Class<?>> classList = new ArrayList<Class<?>>(); String packageDirName = packageName.replace('.', '/'); Enumeration<URL> dirs = null; try { dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName); } catch (IOException e) { log.error("Failed to get resource", e); return null; } while (dirs.hasMoreElements()) { URL url = dirs.nextElement();//file:/D:/E/workspaceGitub/springboot/JSONDemo/target/classes/com/yq/controller String protocol = url.getProtocol();//file //https://docs.oracle.com/javase/7/docs/api/java/net/URL.html //http, https, ftp, file, and jar //本文只需要处理file和jar if ("file".equals(protocol) ) { String filePath = null; try { filePath = URLDecoder.decode(url.getFile(), "UTF-8");///D:/E/workspaceGitub/springboot/JSONDemo/target/classes/com/yq/controller } catch (UnsupportedEncodingException e) { log.error("Failed to decode class file", e); } filePath = filePath.substring(1); getClassesWithAnnotationFromFilePath(packageName, filePath, classList, annotation); } else if ("jar".equals(protocol)) { JarFile jar = null; try { jar = ((JarURLConnection) url.openConnection()).getJarFile(); //扫描jar包文件 并添加到集合中 } catch (Exception e) { log.error("Failed to decode class jar", e); } List<Class<?>> alClassList = new ArrayList<Class<?>>(); findClassesByJar(packageName, jar, alClassList); getClassesWithAnnotationFromAllClasses(alClassList, annotation, classList); } else { log.warn("can't process the protocol={}", protocol); } } return classList; }
private static void findClassesByJar(String pkgName, JarFile jar, List<Class<?>> classes) { String pkgDir = pkgName.replace(".", "/"); Enumeration<JarEntry> entry = jar.entries(); while (entry.hasMoreElements()) { // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文 JarEntry jarEntry = entry.nextElement(); String name = jarEntry.getName(); // 如果是以/开头的 if (name.charAt(0) == '/') { // 获取后面的字符串 name = name.substring(1); } if (jarEntry.isDirectory() || !name.startsWith(pkgDir) || !name.endsWith(".class")) { continue; } //如果是一个.class文件 而且不是目录 // 去掉后面的".class" 获取真正的类名 String className = name.substring(0, name.length() - 6); Class<?> tempClass = loadClass(className.replace("/", ".")); // 添加到集合中去 if (tempClass != null) { classes.add(tempClass); } } } /** * 加载类 * @param fullClsName 类全名 * @return */ private static Class<?> loadClass(String fullClsName ) { try { return Thread.currentThread().getContextClassLoader().loadClass(fullClsName ); } catch (ClassNotFoundException e) { log.error("PkgClsPath loadClass", e); } return null; } //filePath is like this 'D:/E/workspaceGitub/springboot/JSONDemo/target/classes/com/yq/controller' private void getClassesWithAnnotationFromFilePath(String packageName, String filePath, List<Class<?>> classList, Class<? extends Annotation> annotation) { Path dir = Paths.get(filePath);//D:\E\workspaceGitub\springboot\JSONDemo\target\classes\com\yq\controller try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) { for(Path path : stream) { String fileName = String.valueOf(path.getFileName()); // for current dir , it is 'helloworld' //如果path是目录的话, 此处需要递归, boolean isDir = Files.isDirectory(path); if(isDir) { getClassesWithAnnotationFromFilePath(packageName + "." + fileName , path.toString(), classList, annotation); } else { String className = fileName.substring(0, fileName.length() - 6); Class<?> classes = null; String fullClassPath = packageName + "." + className; try { log.info("fullClassPath={}", fullClassPath); classes = Thread.currentThread().getContextClassLoader().loadClass(fullClassPath); } catch (ClassNotFoundException e) { log.error("Failed to find class={}", fullClassPath, e); } if (null != classes && null != classes.getAnnotation(annotation)) { classList.add(classes); } } } } catch (IOException e) { log.error("Failed to read class file", e); } } private void getClassesWithAnnotationFromAllClasses(List<Class<?>> inClassList, Class<? extends Annotation> annotation, List<Class<?>> outClassList) { for(Class<?> myClasss : inClassList) { if (null != myClasss && null != myClasss.getAnnotation(annotation)) { outClassList.add(myClasss); } } }
第二步
根据第一步提供的controller,遍历该类的所有方法,检查该方法是否添加MyChecker注解(MyChecker为自定义的注解)
private void geMethodWithAnnotationFromFilePath(String fullClassPath, Map<String, String> checkIdMethodMap, Class<? extends Annotation> methodAnnotation) { Class<?> classes = null; try { log.info("fullClassPath={}", fullClassPath); classes = Thread.currentThread().getContextClassLoader().loadClass(fullClassPath); Method[] methods = classes.getDeclaredMethods(); for (Method method : methods) { MyChecker myAnnotation = method.getAnnotation(MyChecker.class); if (null != myAnnotation) { checkIdMethodMap.put (myAnnotation.id(), method.getName() ); } } } catch (ClassNotFoundException e) { log.error("Failed to find class={}", fullClassPath, e); }
效果截图
http://dl2.iteye.com/upload/attachment/0132/0836/2c30583b-ee70-368b-b4b7-3cb38e5b1dba.png
发表评论
-
【第七章】 对JDBC的支持 之 7.5 集成Spring JDBC及最佳实践 ——跟我学spring3
2015-09-28 14:58 6597.5 集成Spring JDBC及最佳实践 ... -
【第七章】 对JDBC的支持 之 7.4 Spring提供的其它帮助 ——跟我学spring3【私塾在线原创】
2015-09-28 14:57 6417.4 Spring提供的其它帮助 7.4 ... -
【第七章】 对JDBC的支持 之 7.3 关系数据库操作对象化 ——跟我学spring3
2015-09-28 14:56 5117.3.1 概述 所谓关系数据 ... -
对JDBC的支持 之 7.2 JDBC模板类 ——跟我学spring3
2015-09-28 14:54 6347.2 JDBC模板类 7.2.1 概述 ... -
【第七章】 对JDBC的支持 之 7.1 概述 ——跟我学spring3
2015-09-28 14:53 4667.1 概述 7.1.1 JDBC回顾 ... -
SpringMVC3强大的请求映射规则详解 第六章 注解式控制器详解——跟着我学SpringMVC
2015-07-21 09:40 500声明:本系列都是原创内容,觉得好就顶一个,让更多人知 ... -
SpringMVC3强大的请求映射规则详解 第六章 注解式控制器详解——跟着我学SpringMVC
2015-07-21 09:38 596声明:本系列都是原创内容,觉得好就顶一个,让更多人知道!!写 ... -
【第五章】Spring表达式语言 之 5.4在Bean定义中使用EL—跟我学spring3
2015-05-25 15:36 3745.4.1 xml风格的配置 ... -
【第五章】Spring表达式语言 之 5.3 SpEL语法 ——跟我学spring3
2015-05-25 15:35 5475.3 SpEL语法 5.3.1 基本表达 ... -
【第五章】Spring表达式语言 之 5.1 概述 5.2 SpEL基础 ——跟我学spring3
2015-05-25 15:33 6645.1 概述 5.1.1 ... -
【第四章】 资源 之 4.4 Resource通配符路径 ——跟我学spring3
2015-05-25 15:31 5664.4.1 使用路径通配符加载Resource ... -
【第四章】 资源 之 4.3 访问Resource ——跟我学spring3
2015-05-25 15:29 5894.3.1 ResourceLoader接口 ... -
第四章 Controller接口控制器详解(1)——跟着我学SpringMVC
2014-09-16 09:49 6904.1、Controller简介 Control ... -
第四章 Controller接口控制器详解(1)——跟着我学SpringMVC
2014-09-16 09:48 12074.1、Controller简介 Control ... -
第一章 Web MVC简介 —— 跟我学SpringMVC
2014-09-16 09:46 736Web MVC简介 1.1、Web开发中的请求-响应模型: ... -
第二章 Spring MVC入门 —— 跟我学SpringMVC
2014-09-16 09:44 14482.1、Spring Web MVC是什么 S ... -
第三章 DispatcherServlet详解 ——跟我学SpringMVC
2014-09-16 09:42 7453.1、DispatcherServlet作用 Dispa ... -
第三章 DispatcherServlet详解 ——跟小龙学SpringMVC
2014-09-16 09:36 03.1、DispatcherServlet作用 Dispa ... -
spring配置详解
2014-05-08 15:50 5281.基本配置: <?xml ve ... -
【第三章】 DI 之 3.3 更多DI的知识 ——跟我学spring3 .0
2014-03-03 10:00 7883.3.1 延迟初始化Bean 延迟初始 ...
相关推荐
- **作用**:通过 `@ComponentScan` 注解指定要扫描的包,Spring 会自动查找其中带有 `@Component`、`@Controller`、`@Service` 或 `@Repository` 注解的类,并将其注册为 Bean。 ##### 10. `@Configuration` - **...
`@Configuration`表明当前类是配置类,`@EnableAutoConfiguration`启动自动配置功能,而`@ComponentScan`则扫描并注册所有带有@Component、@Service、@Repository、@Controller等注解的类。 2. **@ResponseBody**:...
在SpringBoot HelloWorld程序中,我们通常会创建一个简单的Controller类,该类中有一个返回"Hello, World!"的RESTful API。下面是一个简单的Controller示例: ```java import org.springframework.web.bind....
在 Spring Boot 中,此类通常包含 `@SpringBootApplication` 注解,该注解会启用 Spring 的自动配置功能、组件扫描和 Spring Web 模块。启动类是应用程序的入口点,当运行该类时,Spring Boot 会初始化并启动整个...
- 配置启动类:创建一个带有`@SpringBootApplication`和`@EnableDubbo`注解的启动类,启用Dubbo功能。 4. **运行与测试**:完成上述步骤后,你可以运行项目,服务提供者和消费者都会启动。由于本DEMO是可直接运行...
在这个例子中,`@MyMonitor`有两个属性:`metricName`和`importance`,它们都带有默认值。 2. 使用注解:在需要监控的方法上使用自定义注解,指定相关指标。 ```java @Service public class MyService { @...
通过 `@ComponentScan`,SpringBoot 会发现并注册带有 `@Component`、`@Service`、`@Repository` 和 `@Controller` 注解的类。 内嵌 Web 服务器如 Tomcat 或 Jetty,使得我们无需额外的步骤就可以启动一个 HTTP ...
这样,我们就创建了一个简单的注解处理器,它可以扫描指定包下所有带有`MyComponent`注解的类,并将它们注册为Spring的bean,bean的名称由注解的`value`属性决定。 最后,为了让Spring知道并执行我们的`...
接下来,在启动类中加入`@ServletComponentScan`注解,以便让Spring Boot在启动时扫描并注册带有`@WebServlet`注解的类。 ```java @SpringBootApplication @ServletComponentScan public class App { public ...
2. 控制器(Controller):这些是 SpringMVC 中处理 HTTP 请求的类,通常带有 `@RestController` 或 `@Controller` 注解,用于接收前端请求并返回响应。 3. 服务(Service):业务逻辑层,处理数据操作和复杂的业务...
- **加载主配置**:找到主配置类,通常是带有@SpringBootApplication注解的类,将其作为配置元数据加载到ApplicationContext。 - **调用ApplicationPreparedEvent**:发布此事件,允许在ApplicationContext准备好...
通常,这将由一个带有`@RestController`注解的控制器类中的方法处理。例如,我们可以有一个名为`HelloController`的类,其中包含一个`hello()`方法,这个方法可能使用`@GetMapping("/hello")`注解来指定HTTP GET请求...
3. **主应用类**:应用的入口通常是带有`@SpringBootApplication`注解的类,它整合了`@Configuration`(配置类)、`@EnableAutoConfiguration`(启用自动配置)和`@ComponentScan`(扫描组件)功能。 4. **Web支持*...
2. **主应用类**:项目中会有个带有`@SpringBootApplication`注解的主类,如`Application.java`,这是SpringBoot应用的入口点。该注解包含了`@SpringBootConfiguration`、`@EnableAutoConfiguration`和`@...
在IDEA中导入`springboothao`项目后,你可以启动主类,通常带有`@SpringBootApplication`注解的类,这将启动SpringBoot应用。应用会自动扫描指定包及其子包下的Bean,进行依赖注入和自动配置。 在SpringBoot项目中...
它会扫描指定的包及其子包,寻找带有@Component、@Service、@Repository和@Controller等注解的类,并将它们纳入Spring容器管理。 2. **配置文件(YAML/Properties)**:SpringBoot支持application.yml或application...
- **定位main应用类**: 主类通常带有`@SpringBootApplication`注解。 **3.3 配置类** - **导入其他配置类**: 使用`@Import`注解导入其他配置类。 - **导入XML配置**: 尽管Spring Boot鼓励使用Java配置,但仍然支持...
**主应用类(Main Application)**:通常会有一个带有`@SpringBootApplication`注解的主类,这个注解集成了`@Configuration`(配置类)、`@EnableAutoConfiguration`(启用自动配置)和`@ComponentScan`(组件扫描)...
- `@ComponentScan`:用于扫描指定包及其子包下带有@Component注解的类,自动注册为Bean。 #### 二、Spring基础回顾 ##### 2.1 IOC(Inversion of Control)基本概念 控制反转是一种设计原则,其核心思想是将...