springmvc学习

本文介绍了在Spring MVC框架下实现安全管控的思路和代码,包括使用@Security注解进行权限控制,以及在初始化和请求处理阶段的实现细节。同时,还讲解了如何实现网页功能,如登录验证、数据查询以及Spring Data JPA的整合,其中登录验证通过Spring MVC拦截器完成。
摘要由CSDN通过智能技术生成

一、实现安全管控

在手写mvc框架得基础上(只完成了请求分发和自定义spring框架),定义注解@Security(有value属性,接收String数组),该注解用于添加在Controller类或者Handler方法上,实现安全管控。

一、思路

定义注解@Security,使用到Controller类上,代表其中的所有Handler方法都要进行安全管控;使用到Handler方法上,代表该方法需要进行安全管控。考虑了四种实现方法:
1.依照自定义spring框架中实现transactional的方式,我们可以使用代理,检查到有Controller类使用了@Security就进行动态代理,在代理类中进行安全检查;
2.使用过滤器Filter,但是过滤器只能拦截请求,无法详细到指定哪些方法处理;
3.使用拦截器Interceptor,很明显这个需要我们自己使用AOP(动态代理)实现;
4.我们映射handler的时候,有存储相应的关系,我们也做类似处理即可,创建一个请求与安全管控相应的关系map,在servlet doPost中添加上相应处理逻辑即可,简单快捷。

二、代码

我们在handlerMapping初始化的时候,读取其中的Security注解,获取其中的用户名,保存到securityMap中。


//securityMapping
    private Map<String,Object> securityMap=new HashMap<String,Object>();

  private void initHandlerMapping() {
   
        if(ioc.isEmpty()) {
   return;}

        for(Map.Entry<String,Object> entry: ioc.entrySet()) {
   
            // 获取ioc中当前遍历的对象的class类型
            Class<?> aClass = entry.getValue().getClass();


            if(!aClass.isAnnotationPresent(LagouController.class)) {
   continue;}

            boolean isAllSecurityMethod=false;
            String[]  SecutiryUser={
   };
            if(aClass.isAnnotationPresent(LagouSecurity.class)) {
   
                isAllSecurityMethod=true;
                LagouSecurity annotation = aClass.getAnnotation(LagouSecurity.class);
                SecutiryUser = annotation.value();
            }


            String baseUrl = "";
            if(aClass.isAnnotationPresent(LagouRequestMapping.class)) {
   
                LagouRequestMapping annotation = aClass.getAnnotation(LagouRequestMapping.class);
                baseUrl = annotation.value(); // 等同于/demo
            }


            // 获取方法
            Method[] methods = aClass.getMethods();
            for (int i = 0; i < methods.length; i++) {
   
                Method method = methods[i];

                //  方法没有标识LagouRequestMapping,就不处理
                if(!method.isAnnotationPresent(LagouRequestMapping.class)) {
   continue;}

                // 如果标识,就处理
                LagouRequestMapping annotation = method.getAnnotation(LagouRequestMapping.class);
                String methodUrl = annotation.value();  // /query
                String url = baseUrl + methodUrl;    // 计算出来的url /demo/query

                if(isAllSecurityMethod){
   
                    securityMap.put(url,SecutiryUser);
                }else{
   
                    if(method.isAnnotationPresent(LagouSecurity.class)) {
   
                        LagouSecurity Mannotation = method.getAnnotation(LagouSecurity.class);
                        SecutiryUser = Mannotation.value();
                        securityMap.put(url,SecutiryUser);
                    }
                }


                // 把method所有信息及url封装为一个Handler
                Handler handler = new Handler(entry.getValue(),method, Pattern.compile(url));


                // 计算方法的参数位置信息  // query(HttpServletRequest request, HttpServletResponse response,String name)
                Parameter[] parameters = method.getParameters();
                for (int j = 0; j < parameters.length; j++) {
   
                    Parameter parameter = parameters[j];

                    if(parameter.getType() == HttpServletRequest.class || parameter.getType() == HttpServletResponse.class) {
   
                        // 如果是request和response对象,那么参数名称写HttpServletRequest和HttpServletResponse
                        handler.getParamIndexMapping().put(parameter.getType().getSimpleName(),j);
                    }else{
   
                        handler.getParamIndexMapping().put(parameter.getName(),j);  // <name,2>
                    }

                }


                // 建立url和method之间的映射关系(map缓存起来)
                handlerMapping.add(handler);

            }


        }

    }

执行doPost的时候,检查我们的securityMap中是否存在相应的数据,若是存在就取检查请求中是否携带username参数,并检查是否属于我们允许的用户。


    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   
        // 处理请求:根据url,找到对应的Method方法,进行调用
        // 获取uri
//        String requestURI = req.getRequestURI();
//        Method method = handlerMapping.get(requestURI);// 获取到一个反射的方法
        // 反射调用,需要传入对象,需要传入参数,此处无法完成调用,没有把对象缓存起来,也没有参数!!!!改造initHandlerMapping();
//        method.invoke() //


        // 根据uri获取到能够处理当前请求的hanlder(从handlermapping中(list))
        Handler handler = getHandler(req);

        if(handler == null) {
   
            resp.getWriter().write("404 not found");
            return;
        }
        String[] usernams= (String[]) securityMap.get( req.getRequestURI());
        if(usernams!=null&& usernams.length>=1){
   
            String username=req.getParameter("username");
            if(username==null||username.equals("")){
   
                resp.getWriter().write("username is empty");
                return;
            }
            if(!Arrays.asList(usernams).contains(username)){
   
                resp.getWriter().write("username"+username+"cannot access");
                return;
            }
        }

        // 参数绑定
        // 获取所有参数类型数组,这个数组的长度就是我们最后要传入的args数组的长度
        Class<?>[] parameterTypes = handler.getMethod().getParameterTypes();


        // 根据上述数组长度创建一个新的数组(参数数组,是要传入反射调用的)
        Object[] paraValues = new Object[parameterTypes.length];

        // 以下就是为了向参数数组中塞值,而且还得保证参数的顺序和方法中形参顺序一致

        Map<String, String[]> parameterMap = req.getParameterMap();

        // 遍历request中所有参数  (填充除了request,response之外的参数)
        for(Map.Entry<String,String[]> param: parameterMap.entrySet()) {
   
            // name=1&name=2   name [1,2]
            String value = StringUtils.join(param.getValue(), ",");  // 如同 1,2

            // 如果参数和方法中的参数匹配上了,填充数据
            if(!handler.getParamIndexMapping().containsKey(param.getKey())) {
   continue;}

            // 方法形参确实有该参数,找到它的索引位置,对应的把参数值放入paraValues
            Integer index = handler.getParamIndexMapping().get(param.getKey());//name在第 2 个位置

            paraValues[index] = val
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值