spring实用知识分享

来源:互联网 发布:大尺度耽美网络剧 编辑:程序博客网 时间:2024/06/06 12:35

最近整理了下之前看到的,用过的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配置文件中配置扫描包

@Componentpublic 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@Componentpublic 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(注意在配置文件中配置扫描包)

@Componentpublic 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 })@Documentedpublic @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 0