spring实用知识分享

最近整理了下之前看到的,用过的spring的一些实用知识,特写出来供同学们参考,感觉前人的成果~

spring容器介绍:
1、 spring容器为父容器,springMvc容器为子容器
2、 父容器由ContextLoaderListener加载,子容器由DispatcherServlet加载
3、 子容器可以访问父容器中的bean,但是父容器不可以访问子容器中的bean
注意点:明确容器之间的关系,明白各自配置文件中的内容的作用域


Spring对于静态变量怎么初始化赋值?
很多时候,我们在工作中需要将一些常用配置写入properties配置文件,然后将值赋给一个静态变量供程序调用,spring默认是没有静态变量赋值的,需要我们自己去实现,请看下面2种方法:
方法一:
1、新建静态变量

public class ConstantUtil {

    // 云OSS公共图片路径(正式路径请用pub_img/,测试路径请用test_pub_img/)
    public static String OSS_PUB_IMG;
    // 云OSS 公共图片前缀url
    public static String OSS_PUB_IMG_URL;

}

2、新建配置文件properties,设置静态变量对应的值
这里写图片描述

3、在spring配置文件中加载配置文件

<!-- 加载配置文件 ,多个用逗号隔开-->
    <context:property-placeholder location="classpath:properties/antx_admin.properties" />

4、新建一个类实现spring的InitializingBean和ServletContextAware接口

public class SystemInitBean implements InitializingBean, ServletContextAware {

    public void setOssPubImg(String ossPubImg) {
        ConstantUtil.OSS_PUB_IMG = ossPubImg;
    }

    public void setOssPubImgUrl(String ossPubImgUrl) {
        ConstantUtil.OSS_PUB_IMG_URL = ossPubImgUrl;
    }

    @Override
    public void setServletContext(ServletContext servletContext) {
        // TODO Auto-generated method stub

    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // TODO Auto-generated method stub

    }

}

5、然后在spring配置文件中注入SystemInitBean这个类,将properties的值赋给静态变量

    <!-- 初始化antx_admin.properties配置文件中的值到静态变量中 -->
    <bean class="com.rightknights.web.admin.listener.SystemInitBean">
        <property name="ossPubImg" value="${OSS_PUB_IMG}"/>
        <property name="ossPubImgUrl" value="${OSS_PUB_IMG_URL}"/>
    </bean> 

方法二
1、同上,新建静态变量
2、在spring配置文件中,通过propertiesFactoryBean加载配置文件

<!--  注意这个id为setting,后面要用到 -->
    <bean id="setting"
        class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="locations">
            <list>
                <value>classpath:properties/antx_admin.properties</value>
            </list>
        </property>
        <property name="fileEncoding" value="UTF-8"></property>
    </bean>

3、新建初始化类,并在spring配置文件中配置扫描包

@Component
public class ConfigProperty {

    private static ConfigProperty insstance;

    public static ConfigProperty getInstance(){
        return insstance;
    }
    public ConfigProperty(){
        insstance = this;
    }

    @Value("#{setting['OSS_PATH']}")
    private String OSS_PATH;

    @Value("#{setting['DOP_URL']}")
    private String DOP_URL;

    public String getOSS_PATH() {
        return OSS_PATH;
    }

    public void setOSS_PATH(String oSS_PATH) {
        OSS_PATH = oSS_PATH;
    }

    public String getDOP_URL() {
        return DOP_URL;
    }

    public void setDOP_URL(String dOP_URL) {
        DOP_URL = dOP_URL;
    }

}

4、调用方法

ConfigProperty.getInstance().getOSS_PATH

spring的@value注解使用
在实际开发中,很多时候也需要对普通变量进行初始化赋值,那么我们可以通过spring的@Value注解来解决
1、新建配置文件

这里写图片描述

2、加载配置文件

<!-- 加载配置文件 ,多个用逗号隔开-->
    <context:property-placeholder location="classpath:properties/antx_admin.properties" />

3、在实际代码中使用

@Value("${demo}")
private String demo;

controller层加事务控制(@Transactional)
基本上spring的事务是配置在service层的,而事务生效也是在spring核心容器中,这是事务一致性保证的,如果我们有需求在controller层配置事务,来控制回滚等,那么就需要以下配置:

1、加入约束(有部分多余的约束,自行处理)

<!-- Bean头部 -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:util="http://www.springframework.org/schema/util" xmlns:task="http://www.springframework.org/schema/task"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-4.0.xsd  
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd  
            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd              
            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
            http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

2、开始事务注解

<!-- controller层事务注解 -->
    <tx:annotation-driven/>

spring之BeanWrapperImpl实用举例
BeanWrapperImpl类是对BeanWrapper接口的默认实现,它包装了一个bean对象,缓存了bean的内省结果,并可以访问bean的属性、设置bean的属性值。BeanWrapperImpl类提供了许多默认属性编辑器,支持多种不同类型的类型转换,可以将数组、集合类型的属性转换成指定特殊类型的数组或集合。用户也可以注册自定义的属性编辑器在BeanWrapperImpl中。我们在实际工作中,可以有很多业务场景用到此类才实现通用方法,见下:
1、 需要将一个集合中所有对象某个具体字段的值全部取出来,以便后续使用,正常做法是循环取(如果后面别的集合也有此情况,又得循环),而通过BeanWrapperImpl,我们可以做一个通用的工具类。
第一个为去重的方法

 public static <T> Set<T> getPropertieSet(Collection<?> collection, String propertyName, Class<T> clazz) {
        Set<T> set = new HashSet<T>();
        if (null != collection) {
            for (Object item : collection) {
                BeanWrapper beanWrapper = new BeanWrapperImpl(item);
                @SuppressWarnings("unchecked")
                T property = (T) beanWrapper.getPropertyValue(propertyName);
                set.add(property);
            }
        }
        return set;
    }

    public static <T> List<T> getProperties(Collection<?> collection, String propertyName, Class<T> clazz) {
        List<T> list = new ArrayList<T>();
        if (null != collection) {
            for (Object item : collection) {
                BeanWrapper beanWrapper = new BeanWrapperImpl(item);
                @SuppressWarnings("unchecked")
                T property = (T) beanWrapper.getPropertyValue(propertyName);
                list.add(property);
            }
        }
        return list;
    }

2、 需要根据集合中某个具体字段分组,取出此字段对应的具体对象来进行后续工作。

 public static <T> List<T> getProperties(Collection<?> collection, String propertyName, Class<T> clazz) {
        List<T> list = new ArrayList<T>();
        if (null != collection) {
            for (Object item : collection) {
                BeanWrapper beanWrapper = new BeanWrapperImpl(item);
                @SuppressWarnings("unchecked")
                T property = (T) beanWrapper.getPropertyValue(propertyName);
                list.add(property);
            }
        }
        return list;
    }

3、

    /**
     * 
      * @author: kuangkuang
      * @Description: 根据collection中T对象的某个属性keyPropertyName;和它对应的具体值,取出对应的该对象
      * @Date: 2016年12月21日 上午11:10:48
      * @param collection
      * @param keyPropertyName
      * @param valuePropertyName
      * @param allClazz
      * @return
      * @throws
     */
    @SuppressWarnings("unchecked")
    public static <K, T> List<T> getBeanByProperty(Collection<T> collection, String keyPropertyName,
            K valuePropertyName, Class<K> allClazz) {
        List<T> result = new ArrayList<T>();
        if (null != collection) {
            for (T item : collection) {
                BeanWrapper beanWrapper = new BeanWrapperImpl(item);
                K property = (K) beanWrapper.getPropertyValue(keyPropertyName);
                if (property .equals(valuePropertyName)) {
                    result.add(item);
                }
            }
        }
        return result;
    }

4、

   /**
     * 根据T中某个字段的值来获取在sources里面存在,在targets里面不存在的集合(支持当前传入字段的属性值为基础类型)
     * 
     * @param sources
     * @param targets
     * @param argumentName(字段名称)
     * @return
     */
    public static <T> List<T> diffCollection(List<T> sources, List<T> targets, String argumentName) {
        List<T> result = new ArrayList<T>();
        if (CollectionUtils.isEmpty(targets)) {
            return result;
        }
        if (CollectionUtils.isEmpty(sources)) {
            return result;
        }
        Map<Object, T> map = initMap(sources, argumentName);
        for (T t : targets) {
            BeanWrapper beanWrapper = new BeanWrapperImpl(t);
            Object value = beanWrapper.getPropertyValue(argumentName);
            if (map.get(value) == null) {
                result.add(t);
            }
        }
        return result;
    }

    private static <T> Map<Object, T> initMap(List<T> sources, String argumentName) {
        Map<Object, T> resultMap = new HashMap<Object, T>();
        for (T t : sources) {
            BeanWrapper beanWrapper = new BeanWrapperImpl(t);
            if (beanWrapper.getPropertyValue(argumentName) == null) {
                throw new RuntimeException("当前属性值为null");
            }
            resultMap.put(beanWrapper.getPropertyValue(argumentName), t);
        }
        return resultMap;
    }

spring之controller层aop编程
实际开发中可能需要对controller每个用户调了什么方法进行一个记录,方便查询,例子如下:
定义一个切点类,对controller进行拦截,在调用controller下面所有方法之前执行前置处理,将登陆用户,ip地址,调了什么方法等信息写入数据库,方便后续管理。

1、 springMvc配置文件开启AspectJ,开启cglib代理(注意加入aop约束信息)

 <!-- 启动AspectJ支持 -->  
    <aop:aspectj-autoproxy proxy-target-class="true"/>  

2、新建切点类(注意在配置文件中配置扫描包)

@Aspect
@Component
public class ControllerAspect {
    private static Logger logger = LoggerFactory.getLogger(ControllerAspect.class);
    @Autowired
    private TbAspectLogService tbAspectLogService;

    @Pointcut("execution(* com.xx.web.admin.controller..*.*(..))")
    public void controller() {
    }

    @Before(value = "controller()")
    public void daBefore(JoinPoint joinPoint) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                .getRequest();
        HttpSession session = request.getSession();
        // 读取session中的用户
        ShiroUserDo user = (ShiroUserDo) session.getAttribute("user");
        if (null == user) {
            return;
        }
        // 请求的IP
        String ip = request.getRemoteAddr();
        try {
            // *========控制台输出=========*//
            System.out.println("=====前置通知开始=====");
            System.out.println("请求方法:"
                    + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
            System.out.println("请求人:" + user.getUserName());
            System.out.println("请求IP:" + ip);
            // *========数据库日志=========*//
            TbAspectLogDo tbAspectLogDo = new TbAspectLogDo();
            tbAspectLogDo.setMethod(
                    (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
            tbAspectLogDo.setType(AspectLogTypeEnum.CONTROLLER.getCode());
            tbAspectLogDo.setRequestIp(ip);
            tbAspectLogDo.setExceptionCode(null);
            tbAspectLogDo.setExceptionDetail(null);
            tbAspectLogDo.setParams(null);
            tbAspectLogDo.setCreater(user.toString());
            long currentTimeMillis = System.currentTimeMillis();
            tbAspectLogDo.setCreateTime(currentTimeMillis);
            tbAspectLogDo.setModifyTime(currentTimeMillis);
            // 保存数据库
            tbAspectLogService.insert(tbAspectLogDo);
            System.out.println("=====前置通知结束=====");
        } catch (Exception e) {
            // 记录本地异常日志
            logger.error("==前置通知异常==");
            logger.error("异常信息:{}", e.getMessage());
        }
    }

}

spring全局异常处理(实现HandlerExceptionResolver方式)
有些时候,我们在程序中可能会漏掉某些异常,导致用户直接看到了异常报错页面,这是非常不人性化的体现,对于这些漏网之鱼,spring提供了全局异常处理方案,如下:

1、实现spring的HandlerExceptionResolver(注意在配置文件中配置扫描包)

@Component
public class xxHandlerExceptionResolver implements HandlerExceptionResolver {

    private static Logger logger = LoggerFactory.getLogger(xxHandlerExceptionResolver.class);
    @Autowired
    private TbAspectLogService tbAspectLogService;
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
        // 把漏网的异常信息记入日志
        logger.error("Catch Exception: ", ex);

        HttpSession session = request.getSession();
        // 读取session中的用户
        ShiroUserDo user = (ShiroUserDo) session.getAttribute("user");
        if (null == user) {
            return new ModelAndView("login");
        }

        // *========数据库日志=========*//
        // 请求的IP
        String ip = request.getRemoteAddr();
        TbAspectLogDo tbAspectLogDo = new TbAspectLogDo();
        tbAspectLogDo.setRequestIp(ip);
        tbAspectLogDo.setExceptionCode(ex.getClass().getName());
        tbAspectLogDo.setExceptionDetail(ex.getMessage());
        tbAspectLogDo.setCreater(user.toString());
        long currentTimeMillis = System.currentTimeMillis();
        tbAspectLogDo.setCreateTime(currentTimeMillis);
        tbAspectLogDo.setModifyTime(currentTimeMillis);
        // 保存数据库
        tbAspectLogService.insert(tbAspectLogDo);

        /* 使用response返回 */
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); // 设置状态码
        response.setContentType(MediaType.APPLICATION_JSON_VALUE); // 设置ContentType
        response.setCharacterEncoding("UTF-8"); // 避免乱码
        response.setHeader("Cache-Control", "no-cache, must-revalidate");
        try {
            response.getWriter().write("{\"success\":false,\"msg\":\"" + ex.getMessage() + "\"}");
        } catch (IOException e) {
            logger.error("与客户端通讯异常:" + e.getMessage(), e);
        }

        return new ModelAndView();

    }

}

自定义注解接收json方式的参数
Spring自带的接收参数的方式有很多,但对于实际开发中可以有一些特殊需求,spring对于这种需求提供了支持,今天以接收json方法的参数为举例,见下:
1、

/**
 * 用来标识一个参数,使之以JSON方式来绑定数据(同一方法上只能出现一个该注解)。
 * 
 * @author kuangkuang
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.PARAMETER })
@Documented
public @interface JsonParam {
    public String value() default "";
}

2、实现spring的HandlerMethodArgumentResolver参数解析器接口



import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.IOUtils;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.util.TypeUtils;


/**
 * 
 * @ClassName: JsonParameterBinder
 * @Description: TODO
 * @author Comsys-kuangkuang
 * @date 2016年11月29日 上午11:53:45
 *
 */
public class JsonParameterBinder implements HandlerMethodArgumentResolver {

    private static final String JSONBODYATTRIBUTE = "JSON_REQUEST_BODY";

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(JsonParam.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
            WebDataBinderFactory binderFactory) throws Exception {

        Class<?> parameterType = parameter.getParameterType();
        String name = parameter.getParameterName();
        if (parameterType.getName().equals(Object.class.getName())) {
            throw new RuntimeException(String.format("no exact type assigned for parameter '%s'", name));
        }
        String body = getRequestBody(webRequest);
        if (body != null) {
            Object obj = null;
            try {
                obj = JSON.parse(body);
            } catch (Exception e) {
                return null;
            }
            return parseResult(parameter, obj);
        }
        return null;
    }

    /**
     * 
      * @author: kuangkuang
      * @Description: 获取json串
      * @Date: 2016年11月28日 上午10:39:56
      * @param webRequest
      * @return
      * @throws
     */
    private String getRequestBody(NativeWebRequest webRequest) {
        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
        String jsonBody = (String) webRequest.getAttribute(JSONBODYATTRIBUTE, NativeWebRequest.SCOPE_REQUEST);
        if (jsonBody == null) {
            try {
                jsonBody = IOUtils.toString(servletRequest.getInputStream());
                webRequest.setAttribute(JSONBODYATTRIBUTE, jsonBody, NativeWebRequest.SCOPE_REQUEST);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return jsonBody;
    }

    /**
     * 
      * @author: kuangkuang
      * @Description: 将JSON对象转换成指定的用户返回值类型
      * @Date: 2016年11月28日 上午10:40:22
      * @param parameter
      * @param resultObject
      * @return
      * @throws JSONException
      * @throws
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    private Object parseResult(MethodParameter parameter, Object resultObject)
            throws JSONException {
        if (resultObject == null) {
            throw new JSONException("result is empty.");
        }

        Object result = null;

        Class<?> parameterType = parameter.getParameterType();

        boolean isArray = parameterType.isArray();
        boolean isCollection = Collection.class.isAssignableFrom(parameterType);

        Class<?> componentType = parameterType.getComponentType();

        if ((isArray || isCollection) && resultObject instanceof JSONArray) {

            if (!isArray) {
                componentType = (Class<?>) (((ParameterizedType) parameter
                        .getGenericParameterType()).getActualTypeArguments()[0]);
            }

            JSONArray jsonArray = (JSONArray) resultObject;
            int size = jsonArray.size();

            if (isArray) {
                result = Array.newInstance(componentType, size);
            } else {
                result = new ArrayList(size);
            }

            for (int i = 0; i < size; i++) {

                Object value = jsonArray.getObject(i, componentType);

                if (isArray) {
                    Array.set(result, i, value);
                } else {
                    ((List) result).add(value);
                }
            }
        } else {
            if (resultObject instanceof JSONObject) {
                result = JSONObject.toJavaObject((JSONObject) resultObject,
                        parameterType);
            } else {
                result = TypeUtils.castToJavaBean(resultObject, parameterType);
            }
        }

        return result;
    }

}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring揭秘 第五版》是一本详尽介绍Spring框架的畅销书籍。本书内容涵盖了Spring框架的各个方面,从基础概念到高级技术应用都有详细阐述。 首先,本书首先介绍了Spring框架的背景和起源,解释了为什么Spring成为Java开发领域的重要框架。接着,它详细解释了Spring的核心概念,例如控制反转(IoC)和面向切面编程(AOP),并提供了示例代码来帮助读者理解这些概念的实际应用。 其次,本书深入讲解了Spring框架的各个模块,包括Spring IOC、Spring AOP、Spring JDBC、Spring MVC等。每个模块都有独立的章节,对其原理、使用方法和实际应用进行了详细说明。同时,本书还对Spring Boot进行了介绍,介绍了如何利用Spring Boot简化Spring应用的开发和部署。 除了框架本身的介绍外,本书还提供了大量的实例和案例来帮助读者理解和应用Spring框架。这些案例涵盖了不同的应用场景,包括Web开发、数据访问、事务管理等,读者可以通过跟随这些案例来学习和实践Spring框架的各种功能。 最后,本书还对Spring框架的最新发展趋势进行了展望,并提供了一些实用的技巧和经验分享。这些内容使得读者可以深入了解Spring框架的内部原理和应用技巧,提高自己在Spring开发中的水平。 综上所述,《Spring揭秘 第五版》是一本详尽介绍Spring框架的权威书籍,适合想要系统学习和掌握Spring框架的开发人员阅读。无论是初学者还是有一定经验的开发人员,都可以从中获得宝贵的知识和实践经验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值