目录
SpringMVC(使用IE执行AJAX时返回JSON出现下载文件/@ResponseBody出现乱码解决方法)
SpringMVC中使用redirect跳转后https变为http
一、Spring使用注解方式实现AOP
Spring对AOP的实现提供了很好的支持。下面我们就使用Spring的注解来完成AOP做一个例子。
首先,为了使用Spring的AOP注解功能,必须导入如下几个包。aspectjrt.jar,aspectjweaver.jar,cglib-nodep.jar.
1、实体bean
public class Person {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2、接口类
public interface PersonService {
public void save(Person person);
public void update(Person person);
public Person getByIdPerson(Long id);
public void delete(Long id);
}
3、实现类
public class PersonServiceImpl implements PersonService{
Map<Long, Person> maps = new HashMap<Long, Person>();
@Override
public void save(Person person) {
System.out.println("***执行save方法***");
maps.put(person.getId(), person);
}
@Override
public void update(Person person) {
System.out.println("***执行update()方法***");
maps.remove(person.getId());
maps.put(person.getId(), person);
}
@Override
public Person getByIdPerson(Long id) {
System.out.println("***执行getByIdPerson()方法***");
return maps.get(id);
}
@Override
public void delete(Long id) {
System.out.println("***执行delete()方法***");
maps.remove(id);
}
}
4、使用Spring注解方式对这个Bean进行方法拦截
@Aspect
public class MyInterceptor {
@Pointcut("execution(* cn.tzz.aop.annotation.service.impl..*.*(..))")
private void anyMethod(){}//定义切点
@Before("anyMethod() && args(person)")
public void doAccessCheck(Person person){
System.out.println(person.getName());
System.out.println("前置通知");
}
@AfterReturning("anyMethod()")
public void doAfter(){
System.out.println("后置通知");
}
@After("anyMethod()")
public void after(){
System.out.println("最终通知");
}
@AfterThrowing("anyMethod()")
public void doAfterThrow(){
System.out.println("异常通知");
}
@Around("anyMethod()")
public Object doBasicProfiling(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
System.out.println("进入环绕通知");
Object object = proceedingJoinPoint.proceed();//执行该方法
System.out.println("退出方法");
return object;
}
}
@Pointcut("execution(* cn.tzz.aop.annotation.service.impl..*.*(..))")
上述是定义方法切入点,execution为执行的意思,*代表任意返回值,然后是包名,.*意思是包下面的所有子包,(..)代表各种方法.
5、在Spring的配置文件中配置Bean,需要打开AOP命名空间
<?xml version="1.0" encoding="UTF-8"?>
<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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="cn.tzz.aop.annotation" />
<aop:aspectj-autoproxy proxy-target-class="true" />
<bean id="personService" class="cn.tzz.aop.annotation.service.impl.PersonServiceImpl"></bean>
<bean id="myInterceptor" class="cn.tzz.aop.annotation.MyInterceptor"></bean>
</beans>
6、测试
public class TestAop {
private static ApplicationContext ctx = null;
private static PersonService personService = null;
static{
ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
personService = (PersonService)ctx.getBean("personService");
}
public void testSave(){
Person person = new Person();
person.setId(1L);
person.setName("abc");
personService.save(person);
}
public void testGetByIdPerson(){
Person p = personService.getByIdPerson(1L);
System.out.println(p.getId()+"---"+p.getName());
}
public void testUpdate(){
Person person = new Person();
person.setId(1L);
person.setName("abc_1");
personService.update(person);
}
public void testDelete(){
personService.delete(1L);
}
@Test
public void testInteceptor(){
testSave();
// testGetByIdPerson();
// testUpdate();
// testGetByIdPerson();
// testDelete();
// testGetByIdPerson();
}
}
7、测试结果
abc
前置通知
进入环绕通知
***执行save方法***
后置通知
退出方法
最终通知
二、Spring使用XML方式实现AOP
Spring对AOP的实现提供了很好的支持。下面我们就使用Spring的XML来完成AOP做一个例子。
首先,为了使用Spring的AOP注解功能,必须导入如下几个包。aspectjrt.jar,aspectjweaver.jar,cglib-nodep.jar.
1、实体bean
public class Person {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2、接口类
public interface PersonService {
public void save(Person person);
public void update(Person person);
public Person getByIdPerson(Long id);
public void delete(Long id);
}
3、实现类
public class PersonServiceImpl implements PersonService{
Map<Long, Person> maps = new HashMap<Long, Person>();
@Override
public void save(Person person) {
System.out.println("***执行save方法***");
maps.put(person.getId(), person);
}
@Override
public void update(Person person) {
System.out.println("***执行update()方法***");
maps.remove(person.getId());
maps.put(person.getId(), person);
}
@Override
public Person getByIdPerson(Long id) {
System.out.println("***执行getByIdPerson()方法***");
return maps.get(id);
}
@Override
public void delete(Long id) {
System.out.println("***执行delete()方法***");
maps.remove(id);
}
}
4、定义Aspect
public class MyInterceptor {
/**在核心业务执行前执行,不能阻止核心业务的调用*/
public void doBefore(JoinPoint joinPoint) {
//可通过joinPoint来获取所需要的内容
Object[] objects = joinPoint.getArgs();
Person person = (Person) objects[0];
System.out.println("前置通知:"+person.getName());
}
/** 核心业务逻辑退出后(包括正常执行结束和异常退出),执行此Advice @param joinPoint */
public void doAfter(JoinPoint joinPoint) {
System.out.println("最终通知");
}
/**
* 核心业务逻辑调用正常退出后,不管是否有返回值,正常退出后,均执行此Advice
* @param joinPoint
*/
public void doAfterReturning(JoinPoint joinPoint) {
System.out.println("后置通知");
}
/**异常通知*/
public void doAfterThrowing(Throwable ex) {
System.out.println("异常通知:"+ex.getMessage());
}
/**环绕通知*/
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("进入环绕通知");
Object object = pjp.proceed();//执行该方法
System.out.println("退出方法");
return object;
}
}
5、在Spring的XML配置文件中配置AOP
<?xml version="1.0" encoding="UTF-8"?>
<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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="cn.tzz.aop.annotation" />
<!--AOP 注解 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<bean id="personService" class="cn.tzz.aop.annotation.service.impl.PersonServiceImpl"></bean>
<bean id="myInterceptor" class="cn.tzz.aop.annotation.MyInterceptor"></bean>
<!--XML 注解 -->
<bean id="personXmlService" class="cn.tzz.aop.xml.service.impl.PersonServiceImpl"></bean>
<bean id="myXmlInterceptor" class="cn.tzz.aop.xml.MyInterceptor"></bean>
<aop:config>
<aop:aspect id="aspect" ref="myXmlInterceptor">
<!--定义切点 -->
<aop:pointcut id="myPoint" expression="execution(* cn.tzz.aop.xml.
service.impl..*.*(..))"/>
<aop:before method="doBefore" arg-names="person" pointcut-ref="myPoint"/>
<aop:after method="doAfter" pointcut-ref="myPoint"/>
<aop:after-returning method="doAfterReturning" pointcut-ref="myPoint"/>
<aop:after-throwing method="doAfterThrowing" throwing="ex"
pointcut-ref="myPoint"/>
<aop:around method="doAround" pointcut-ref="myPoint"/>
</aop:aspect>
</aop:config>
</beans>
6、测试
public class TestAop {
private static ApplicationContext ctx = null;
private static PersonService personService = null;
static{
ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
personService = (PersonService)ctx.getBean("personXmlService");
}
public void testSave(){
Person person = new Person();
person.setId(1L);
person.setName("abc");
personService.save(person);
}
public void testGetByIdPerson(){
Person p = personService.getByIdPerson(1L);
System.out.println(p.getId()+"---"+p.getName());
}
public void testUpdate(){
Person person = new Person();
person.setId(1L);
person.setName("abc_1");
personService.update(person);
}
public void testDelete(){
personService.delete(1L);
}
@Test
public void testInteceptor(){
testSave();
// testGetByIdPerson();
// testUpdate();
// testGetByIdPerson();
// testDelete();
// testGetByIdPerson();
}
}
7、测试结果
前置通知:abc
进入环绕通知
***执行save方法***
最终通知
后置通知
退出方法
SpringMVC(使用IE执行AJAX时返回JSON出现下载文件/@ResponseBody出现乱码解决方法)
一、避免IE执行AJAX时,返回JSON出现下载文件
<!-- 避免IE执行AJAX时,返回JSON出现下载文件 -->
<bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>
<!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="mappingJacksonHttpMessageConverter" /><!-- json转换器 -->
</list>
</property>
</bean>
二、使用@ResponseBody出现乱码解决方法
1、 RequestMapping
@Controller
@RequestMapping(value = "/test")
public class TestController {
@ResponseBody
@RequestMapping(value = "/test", method = {RequestMethod.GET})
public String test() {
return "中文";
}
}
2、原因是org.springframework.http.converter.StringHttpMessageConverter类默认编码是IOS-8859-1
3、解决方法
3.1、自己定义一个HttpMessageConverter<String>的实现类即可解决问题。
public class UTF8StringHttpMessageConverter extends AbstractHttpMessageConverter<String> {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private final List<Charset> availableCharsets;
private boolean writeAcceptCharset = true;
public UTF8StringHttpMessageConverter() {
super(new MediaType("text", "plain", DEFAULT_CHARSET), MediaType.ALL);
this.availableCharsets = new ArrayList<Charset>(Charset.availableCharsets().values());
}
public void setWriteAcceptCharset(boolean writeAcceptCharset) {
this.writeAcceptCharset = writeAcceptCharset;
}
@Override
public boolean supports(Class<?> clazz) {
return String.class.equals(clazz);
}
@Override
protected String readInternal(@SuppressWarnings("rawtypes") Class clazz, HttpInputMessage inputMessage) throws IOException {
Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType());
return FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset));
}
@Override
protected Long getContentLength(String s, MediaType contentType) {
Charset charset = getContentTypeCharset(contentType);
try {
return (long) s.getBytes(charset.name()).length;
}
catch (UnsupportedEncodingException ex) {
throw new InternalError(ex.getMessage());
}
}
@Override
protected void writeInternal(String s, HttpOutputMessage outputMessage) throws IOException {
if (writeAcceptCharset) {
outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets());
}
Charset charset = getContentTypeCharset(outputMessage.getHeaders().getContentType());
FileCopyUtils.copy(s, new OutputStreamWriter(outputMessage.getBody(), charset));
}
protected List<Charset> getAcceptedCharsets() {
return this.availableCharsets;
}
private Charset getContentTypeCharset(MediaType contentType) {
if (contentType != null && contentType.getCharSet() != null) {
return contentType.getCharSet();
}
else {
return DEFAULT_CHARSET;
}
}
}
<mvc:annotation-driven conversion-service="conversion-service" validator="validator">
<mvc:message-converters register-defaults="false">
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
<bean class="my.pkg.UTF8StringHttpMessageConverter" />
</mvc:message-converters>
</mvc:annotation-driven>
3.2、设置StringHttpMessageConverter编码
<mvc:annotation-driven conversion-service="conversion-service" validator="validator">
<mvc:message-converters>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
SpringMVC中使用redirect跳转后https变为http
方法一:配置文件修改ViewResolver的 redirectHttp10Compatible 属性,这个属性是为了兼容 http1.0协议
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/" />
<property name="suffix" value=".jsp" />
<property name="redirectHttp10Compatible" value="false" />
</bean>
方法二:在代码中不直接用 return "redirect:/xxx",而改为使用
modelAndView.setView(new RedirectView("your redirect URL",true,false));
Spring bean注入的方式
一 setter方法注入
配置文件如下:
<bean id="helloAction" class="org.yoo.action.SpringSetterHelloAction">
<!-- setter injection using the nested <ref/> element -->
<property name="helloservice"><ref bean="helloService"/></property>
<!--可以不设置类型 -->
<property name="name" value="yoo"></property>
</bean>
action实现类中代码:
private IHelloService helloservice;
private String name ;
public void sayHello(){
helloservice.sayHello();
System.out.println(this.name);
}
public void setHelloservice(IHelloService helloservice) {
this.helloservice = helloservice;
}
public void setName(String name) {
this.name = name;
}
这里的name和helloservice都采用属性的setter方法注入。即类中设置一个全局属性,并对属性有setter方法,以供容器注入。
二 构造器注入
spring也支持构造器注入,也即有些资料中的构造子或者构造函数注入。
先看配置文件:
<!--普通构造器注入-->
<bean id="helloAction" class="org.yoo.action.ConstructorHelloAction">
<!--type 必须为java.lang.String 因为是按类型匹配的,不是按顺序匹配-->
<constructor-arg type="java.lang.String" value="yoo"/>
<!-- 也可以使用index来匹配-->
<!--<constructor-arg index="1" value="42"/>-->
<constructor-arg><ref bean="helloService"/></constructor-arg>
</bean>
action实现类中代码:
private HelloServiceImpl helloservice;
private String name ;
public SpringConstructorHelloAction(HelloServiceImpl helloservice,String name){
this.helloservice = helloservice;
this.name = name ;
}
@Override
public void sayHello() {
helloservice.sayHello();
System.out.println(this.name);
}
同样设置2个属性,然后在构造函数中注入。
三静态工厂注入
配置文件如下:
<!--静态工厂构造注入-->
<!--注意这里的class 带factory-method参数-->
<!--factory-method的值是FactoryHelloAction中的工厂方法名createInstance-->
<bean id="helloAction" class="org.yoo.di.FactoryHelloAction" factory-method="createInstance">
<constructor-arg type="java.lang.String" value="yoo"/>
<constructor-arg><ref bean="helloService"/></constructor-arg>
</bean>
action实现类:
private HelloServiceImpl helloservice;
private String name = null;
private SpringFactoryHelloAction(String name ,HelloServiceImpl helloservice){
this.helloservice = helloservice ;
this.name = name ;
}
public static SpringFactoryHelloAction createInstance(String name ,HelloServiceImpl helloservice) {
SpringFactoryHelloAction fha = new SpringFactoryHelloAction (name,helloservice);
// some other operations
return fha;
}
@Override
public void sayHello() {
helloservice.sayHello();
System.out.println(this.name);
}
四 无配置文件注入(自动注入)
上面三种方法都需要编写配置文件,在spring2.5中还提供了不编写配置文件的ioc实现。需要注意的是,无配置文件指bean之间依赖,不基于配置文件,而不是指没有spring配置文件。
配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean id="helloService" class="org.yoo.service.HelloServiceImpl">
</bean>
<bean id="helloAction" class="org.yoo.action.AutowiredHelloAction">
</bean>
</beans>
可见上面只是设置了helloService和helloAction两个bean,并没有设置helloAction对helloService的依赖。
另外<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
是必须的,有此才支持自动注入。
action实现类:
//属性自动装载,在属性上加上 @Autowired注释,spring会自动注入HelloService
@Autowired
private HelloService helloservice;
@Override
public void sayHello() {
helloservice.sayHello();
}
//构造器自动注入:
@Autowired
public SpringAutowiredHelloAction(HelloServiceImpl helloservice){
this.helloservice = helloservice;
}
//setter方法自动注入:
@Autowired
public void setHelloservice(HelloService helloservice) {
this.helloservice = helloservice;
}
最后在spring的reference文档中有提到,如果不使用自动注入,尽量使用setter方法,一般通用的也是使用setter方法。
而使用自动注入还是配置文件方式,如果jdk低于1.5或者spring不是2.5,就只能够使用配置文件方式了。其它的就看实际项目选择了。
@Resource和@Autowire的区别
使用@Autowire或者@Resource注解方式进行装配,这两个注解的区别是:
@Autowire默认按照类型装配,默认情况下它要求依赖对象必须存在如果允许为null,可以设置它required属性为false,如果我们想使用按照名称装配,可以结合@Qualifier注解一起使用;
@Resource默认按照名称装配,当找不到与名称匹配的bean才会按照类型装配,可以通过name属性指定,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象.
注意:如果没有指定name属性,并且按照默认的名称仍然找不到依赖的对象时候,会回退到按照类型装配,但一旦指定了name属性,就只能按照名称装配了