Java中高级面试题总览(三)(1)

简介: Java中高级面试题总览(三)

一、Spring面试题:

1.1、什么是控制反转(IOC)?什么是依赖注入?

ioc和依赖注入的概念差不多

Spring中的 org.springframework.beans 包和 org.springframework.context包构成了Spring框架IoC容器的基础。

BeanFactory 接口提供了一个先进的配置机制,使得任何类型的对象的配置成为可能。

依赖注入是在编译阶段尚未知所需的功能是来自哪个的类的情况下,将其他对象所依赖的功能对象实例化的模式

在Java中依赖注入有以下三种实现方式:

构造器注入

Setter方法注入

接口注入

1.2、@Component、@Repository   @Service、@Controller有什么区别?

看字面含义,很容易却别出其中三个:
@Controller   控制层,就是我们的action层
@Service        业务逻辑层,就是我们的service或者manager层
@Repository  持久层,就是我们常说的DAO层
而@Component  (字面意思就是组件),它在你确定不了事哪一个层的时候使用。
其实,这四个注解的效果都是一样的,spring都会把它们当做需要注入的Bean加载在上下文中;
但是在项目中,却建议你严格按照除Componen的其余三个注解的含义使用在项目中。这对分层结构的web架构很有好处!!

1.3、Spring框架中的单例bean是线程安全的吗?

不,Spring框架中的单例bean不是线程安全的。

1.4、 解释Spring框架中bean的生命周期(重点)。

  • Spring容器 从XML 文件中读取bean的定义,并实例化bean。
  • Spring根据bean的定义填充所有的属性。
  • --------------------------------------------------------------------(实例化之后调用的回调方法)-------------
  • 如果bean实现了BeanNameAware 接口,Spring 传递bean 的ID 到 setBeanName方法。
  • 如果Bean 实现了 BeanFactoryAware 接口, Spring传递beanfactory 给setBeanFactory 方法。
  • 如果有任何与bean相关联的BeanFactoryPostProcessor,Spring会在postProcessBeanFactory()方法内调用它们。(典型应用PropertyPlaceholderConfigurer)
  • 如果bean实现IntializingBean了,调用它的afterPropertySet方法,如果bean声明了初始化方法,调用此初始化方法。
  • 如果有BeanPostProcessors 和bean 关联,这些bean的postProcessAfterInitialization() 方法将被调用。
  • --------------------------------------------------------------------(销毁之调用的回调方法)-------------
  • 如果bean实现了 DisposableBean,它将调用destroy()方法。
  • --------------------------------------------------------------------------------------------------------------------

1.5、解释AOP

AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码降低模块间的耦合度,并有利于未来的可拓展性和可维护性

Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib

1.6、Spring有几种配置方式?

将Spring配置到应用开发中有以下三种方式:

  1. 基于XML的配置
  2. 基于注解的配置(常用)
  3. 基于Java的配置

1.7、关于面向切面编程的一些术语

  • 切面(Aspect): 切面用于组织多个Advice,Advice放在切面中定义
  • 连接点(Joinpoint): 程序执行过程中明确的点,如方法的调用,或者异常的抛出。在Spring AOP中,连接点总是方法的调用
  • 增强处理(Advice): AOP框架在特定的切入点执行的增强处理。处理有“around”、“before”和“after”等类型
  • 切入点(Pointcut): 可以插入增强处理的连接点。简而言之,当某个连接点满足指定要求时,该连接点将被添加增强处理,该连接点也就变成了切入点

1.8、Spring中自动装配的方式有哪些?

  1. no:这是Spring框架的默认设置,在该设置下自动装配是关闭的,开发者需要自行在bean定义中用标签明确的设置依赖关系。
  2. byName:该选项可以根据bean名称设置依赖关系。当向一个bean中自动装配一个属性时,容器将根据bean的名称自动在在配置文件中查询一个匹配的bean。如果找到的话,就装配这个属性,如果没找到的话就报错。
  3. byType:该选项可以根据bean类型设置依赖关系。当向一个bean中自动装配一个属性时,容器将根据bean的类型自动在在配置文件中查询一个匹配的bean。如果找到的话,就装配这个属性,如果没找到的话就报错。
  4. constructor:造器的自动装配和byType模式类似,但是仅仅适用于与有构造器相同参数的bean,如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
  5. autodetect:该模式自动探测使用构造器自动装配或者byType自动装配。首先,首先会尝试找合适的带参数的构造器,如果找到的话就是用构造器自动装配,如果在bean内部没有找到相应的构造器或者是无参构造器,容器就会自动选择byTpe的自动装配方式。

1.9、Spring Scope

singleton:一个容器中只存在一个实例,所有对该类型bean的依赖都引用这一单一实例

prototype:容器在getBean(),会每次都重新生成一个新的对象给请求方

request:为每个http的request创建一个bean

session:Spring容器会为每个独立的session创建属于自己的全新的UserPreferences实例

global session:global session只有应用在基于porlet的web应用程序中才有意义,他映射到porlet的global范围的session,如果普通的servlet的web 应用中使用了这个scope,容器会把它作为普通的session的scope对待。

1.10、请举例说明如何在Spring中注入一个Java Collection

Spring提供了以下四种集合类的配置元素:
<list> :   该标签用来装配可重复的list值。
<set> :    该标签用来装配没有重复的set值。
<map>:   该标签可用来注入键和值可以为任何类型的键值对。
<props> : 该标签支持注入键和值都是字符串类型的键值对。

1.11、Spring 框架中都用到了哪些设计模式?

Spring框架中使用到了大量的设计模式,下面列举了比较有代表性的:
工厂设计模式 : Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。
代理设计模式 : Spring AOP 功能的实现。
单例设计模式 : Spring 中的 Bean 默认都是单例的。
模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller

1.12、Spring MVC的工作原理是怎样的?

答:Spring MVC的工作原理如下图所示:

① 客户端的所有请求都交给前端控制器DispatcherServlet来处理,它会负责调用系统的其他模块来真正处理用户的请求。

② DispatcherServlet收到请求后,将根据请求的信息(包括URL、HTTP协议方法、请求头、请求参数、Cookie等)以及HandlerMapping的配置找到处理该请求的Handler(任何一个对象都可以作为请求的Handler)。

③在这个地方Spring会通过HandlerAdapter对该处理器进行封装。

④ HandlerAdapter是一个适配器,它用统一的接口对各种Handler中的方法进行调用。

⑤ Handler完成对用户请求的处理后,会返回一个ModelAndView对象给DispatcherServlet,ModelAndView顾名思义,包含了数据模型以及相应的视图的信息。

⑥ ModelAndView的视图是逻辑视图,DispatcherServlet还要借助ViewResolver完成从逻辑视图到真实视图对象的解析工作。

⑦ 当得到真正的视图对象后,DispatcherServlet会利用视图对象对模型数据进行渲染。

⑧ 客户端得到响应,可能是一个普通的HTML页面,也可以是XML或JSON字符串,还可以是一张图片或者一个PDF文件。

备注:源码类问题最好自己动手去断点查看印象更加深刻

1.13、Spring初始化Mybatis的过程:

1MapperScannerConfigurer根据spring的xml配置文件中的包路径来初始化以后需要映射的信息
2根据classpath找到mapper的xml配置
3获取到sqlSessionFectory
4调用Mybatis里的checkDaoConfig检查配置文件是否出错

1.14、Spring中如何让A和B两个bean按顺序加载

可能有些场景中,bean A 间接依赖 bean B。如Bean B应该需要更新一些全局缓存,可能通过单例模式实现且没有在spring容器注册,bean A需要使用该缓存;因此,如果bean B没有准备好,bean A无法访问

解决方法:在bean A上使用@DependsOn注解,告诉容器bean B应该先被初始化。

1.15、Spring Bean 的生命周期

一、单一Bean
创建过程
1. 实例化; 
2. 设置属性值; 
3. 如果实现了BeanNameAware接口,调用setBeanName设置Bean的ID或者Name; 
4. 如果实现BeanFactoryAware接口,调用setBeanFactory 设置BeanFactory; 
5. 如果实现ApplicationContextAware,调用setApplicationContext设置ApplicationContext 
6. 调用BeanPostProcessor的预先初始化方法; 
7. 调用InitializingBean的afterPropertiesSet()方法; 
8. 调用定制init-method方法; 
9. 调用BeanPostProcessor的后初始化方法;
销毁过程
1. 调用DisposableBean的destroy(); 
2. 调用定制的destroy-method方法;
二、多个Bean的先后顺序
优先加载BeanPostProcessor的实现Bean
按Bean文件和Bean的定义顺序,确定bean的装载顺序(即使加载多个spring文件时存在id覆盖)
“设置属性值”(第2步)时,遇到ref,则在“实例化”(第1步)之后先加载ref的id对应的bean
AbstractFactoryBean的子类,在第6步之后,会调用createInstance方法,之后会调用getObjectType方法
BeanFactoryUtils类也会改变Bean的加载顺序

1.16、Spring 事务七中传播行为

这里以A业务和B业务之间如何传播事务为例说明:

①、PROPAGATION_REQUIRED :required , 必须。默认值,A如果有事务,B将使用该事务;如果A没有事务,B将创建一个新的事务。

②、PROPAGATION_SUPPORTS:supports ,支持。A如果有事务,B将使用该事务;如果A没有事务,B将以非事务执行。

③、PROPAGATION_MANDATORY:mandatory ,强制。A如果有事务,B将使用该事务;如果A没有事务,B将抛异常。

④、PROPAGATION_REQUIRES_NEW :requires_new,必须新的。如果A有事务,将A的事务挂起,B创建一个新的事务;如果A没有事务,B创建一个新的事务。

⑤、PROPAGATION_NOT_SUPPORTED :not_supported ,不支持。如果A有事务,将A的事务挂起,B将以非事务执行;如果A没有事务,B将以非事务执行。

⑥、PROPAGATION_NEVER :never,从不。如果A有事务,B将抛异常;如果A没有事务,B将以非事务执行。

⑦、PROPAGATION_NESTED :nested ,嵌套。A和B底层采用保存点机制,形成嵌套事务。

PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行.

PROPAGATION_NESTED 理解Nested的关键是savepoint。他与PROPAGATION_REQUIRES_NEW的区别是,PROPAGATION_REQUIRES_NEW另起一个事务,将会与他的父事务相互独立,而Nested的事务和他的父事务是相依的,他的提交是要等和他的父事务一块提交的。也就是说,如果父事务最后回滚,他也要回滚的。 而Nested事务的好处也是他有一个savepoint。

1.17、在Spring 事务管理中,定义的隔离级别

①、ISOLATION_DEFAULT:使用后端数据库默认的隔离级别
②、ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻
读或不可重复读
③、ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复
读仍有可能发生
④、ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所
修改,可以阻止脏读和不可重复读,但幻读仍有可能发生
⑤、ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以
及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表

1.17、在Spring  事务超时和、回滚规则

  为了使应用程序很好地运行,事务不能运行太长的时间。因为事务可能涉及对后端数据库的锁定,所以长时间的事务会不必要的占用数据库资源。事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束。

  事务五边形的最后一个方面是一组规则,这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚(这一行为与EJB的回滚行为是一致的) 。但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。

1.18、Spring事务异常回滚,捕获异常不抛出就不会回滚

   默认spring事务只在发生未被捕获的 runtimeexcetpion时才回滚。  
   spring aop  异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方
法的异常,才能进行回滚,默认情况下aop只捕获runtimeexception的异常,但可以通过  
配置来捕获特定的异常并回滚  
  换句话说在service的方法中不使用try catch 或者在catch中最后加上throw new 
runtimeexcetpion(),这样程序异常时才能被aop捕获进而回滚
解决方案: 
  方案1.例如service层处理事务,那么service中的方法中不做异常捕获,或者在catch语句中最后增加throw 
new RuntimeException()语句,以便让aop捕获异常再去回滚,并且在service上层(webservice客户端,
view层action)要继续捕获这个异常并处理
  方案2.在service层方法的catch语句中增加:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上
层就无需去处理异常

1.19、BeanFactory与ApplicationContext的区别

BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样,我们就不能发现一些存在的Spring的配置问题。

负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期

ApplicationContext是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误。 相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。 ApplicationContext除了提供上述BeanFactory所能提供的功能之外,还提供了更完整的框架功能

a. 国际化支持

b. 资源访问:Resource rs = ctx. getResource(“classpath:config.properties”), “file:c:/config.properties”

c. 事件传递:通过实现ApplicationContextAware接口

1.20、 SpringIOC getBean() 的代码逻辑

1、转化beanName(传入的参数可能是别名)

2、从缓存中加载单例

3、如果缓存中得到了bean,就要对bean进行实例化(只是最原始的bean状态)

4、原型模式下要进行循环依赖检查

5、如果缓存中没有的话直接去父类工厂parentBeanFactory加载

6、寻杂bean依赖的某些属性

7、针对不同的scope创建bean

1.21、 Spring AOP 和 AspectJ AOP 有什么区别?

Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。

Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。AspectJ 相比于 Spring AOP 功能更加强大,但是 Spring AOP 相对来说更简单,

如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ ,它比Spring AOP 快很多。


二、网站性能优化面试题:

备注:设计类问题考察的目的是懂得理论后能更好的实践

1、你用过的网站前端优化的技术有哪些?

① 浏览器访问优化:
- 减少HTTP请求数量:合并CSS、合并JavaScript、合并图片(CSS Sprite)
- 使用浏览器缓存:通过设置HTTP响应头中的Cache-Control和Expires属性,将CSS、JavaScript、图片等在
浏览器中缓存,当这些静态资源需要更新时,可以更新HTML文件中的引用来让浏览器重新请求新的资源
- 启用压缩
- CSS前置,JavaScript后置
- 减少Cookie传输
② CDN加速:CDN(Content Distribute Network)的本质仍然是缓存,将数据缓存在离用户最近的地方,CDN
通常部署在网络运营商的机房,不仅可以提升响应速度,还可以减少应用服务器的压力。当然,CDN缓存的通常都
是静态资源。
③ 反向代理:反向代理相当于应用服务器的一个门面,可以保护网站的安全性,也可以实现负载均衡的功能,当然
最重要的是它缓存了用户访问的热点资源,可以直接从反向代理将某些内容返回给用户浏览器。

 

2、大型网站在架构上应当考虑哪些问题?

答:

- 分层:分层是处理任何复杂系统最常见的手段之一,将系统横向切分成若干个层面,每个层面只承担单一的职责,然后通过下层为上层提供的基础设施和服务以及上层对下层的调用来形成一个完整的复杂的系统。计算机网络的开放系统互联参考模型(OSI/RM)和Internet的TCP/IP模型都是分层结构,大型网站的软件系统也可以使用分层的理念将其分为持久层(提供数据存储和访问服务)、业务层(处理业务逻辑,系统中最核心的部分)和表示层(系统交互、视图展示)。需要指出的是:(1)分层是逻辑上的划分,在物理上可以位于同一设备上也可以在不同的设备上部署不同的功能模块,这样可以使用更多的计算资源来应对用户的并发访问;(2)层与层之间应当有清晰的边界,这样分层才有意义,才更利于软件的开发和维护。

- 分割:分割是对软件的纵向切分。我们可以将大型网站的不同功能和服务分割开,形成高内聚低耦合的功能模块(单元)。在设计初期可以做一个粗粒度的分割,将网站分割为若干个功能模块,后期还可以进一步对每个模块进行细粒度的分割,这样一方面有助于软件的开发和维护,另一方面有助于分布式的部署,提供网站的并发处理能力和功能的扩展。

- 分布式:可以将分布在各处的资源综合利用。而这种利用对用户而言是透明的,可以将负载由单个节点转移到多个,从而提高效率,分布式技术可以避免由于单个节点失效而使整个系统崩溃的危险,

- 集群:集群使得有更多的服务器提供相同的服务,可以更好的提供对并发的支持,解决了数据库宕机带来的单点数据库不能访问的问题;

(分布式,从窄意上理解,也跟集群差不多, 但是它的组织比较松散,不像集群,有一个组织性,一台服务器垮了,其它的服务器可以顶上来。 分布式的每一个节点,都完成不同的业务,一个节点垮了,那这个业务就不可访问了)

-负载均衡: 有效的降低了单台 机器的访问负载,降低了宕机的可能性;

- 缓存:所谓缓存就是用空间换取时间的技术,将数据尽可能放在距离计算最近的位置。使用缓存是网站优化的第一定律。我们通常说的CDN、反向代理、热点数据都是对缓存技术的使用。

- 异步:异步是实现软件实体之间解耦合的又一重要手段。异步架构是典型的生产者消费者模式,二者之间没有直接的调用关系,只要保持数据结构不变,彼此功能实现可以随意变化而不互相影响,这对网站的扩展非常有利。

-冗余:各种服务器都要提供相应的冗余服务器以便在某台或某些服务器宕机时还能保证网站可以正常工作,同时也提供了灾难恢复的可能性。冗余是网站高可用性的重要保证。

-读写分离:最大限度了提高了应用中读取 (Read)数据的速度和并发量。

3、什么是XSS攻击?什么是SQL注入攻击?什么是CSRF攻击?

答:

- XSS(Cross Site Script,跨站脚本攻击)是向网页中注入恶意脚本在用户浏览网页时在用户浏览器中执行恶意脚本的攻击方式。跨站脚本攻击分有两种形式:反射型攻击(诱使用户点击一个嵌入恶意脚本的链接以达到攻击的目标,目前有很多攻击者利用论坛、微博发布含有恶意脚本的URL就属于这种方式)和持久型攻击(将恶意脚本提交到被攻击网站的数据库中,用户浏览网页时,恶意脚本从数据库中被加载到页面执行,QQ邮箱的早期版本就曾经被利用作为持久型跨站脚本攻击的平台)。XSS虽然不是什么新鲜玩意,但是攻击的手法却不断翻新,防范XSS主要有两方面:消毒(对危险字符进行转义)和HttpOnly(防范XSS攻击者窃取Cookie数据)。

- SQL注入攻击是注入攻击最常见的形式(此外还有OS注入攻击(Struts 2的高危漏洞就是通过OGNL实施OS注入攻击导致的)),当服务器使用请求参数构造SQL语句时,恶意的SQL被嵌入到SQL中交给数据库执行。SQL注入攻击需要攻击者对数据库结构有所了解才能进行,攻击者想要获得表结构有多种方式:(1)如果使用开源系统搭建网站,数据库结构也是公开的(目前有很多现成的系统可以直接搭建论坛,电商网站,虽然方便快捷但是风险是必须要认真评估的);(2)错误回显(如果将服务器的错误信息直接显示在页面上,攻击者可以通过非法参数引发页面错误从而通过错误信息了解数据库结构,Web应用应当设置友好的错误页,一方面符合最小惊讶原则,一方面屏蔽掉可能给系统带来危险的错误回显信息);(3)盲注。防范SQL注入攻击也可以采用消毒的方式,通过正则表达式对请求参数进行验证,此外,参数绑定也是很好的手段,这样恶意的SQL会被当做SQL的参数而不是命令被执行,JDBC中的PreparedStatement就是支持参数绑定的语句对象,从性能和安全性上都明显优于Statement。

- CSRF攻击(Cross Site Request Forgery,跨站请求伪造)是攻击者通过跨站请求,以合法的用户身份进行非法操作(如转账或发帖等)。CSRF的原理是利用浏览器的Cookie或服务器的Session,盗取用户身份。防范CSRF的主要手段是识别请求者的身份,主要有以下几种方式:(1)在表单中添加令牌(token);(2)验证码;(3)检查请求头中的Referer(前面提到防图片盗链接也是用的这种方式)。令牌和验证都具有一次消费性的特征,因此在原理上一致的,但是验证码是一种糟糕的用户体验,不是必要的情况下不要轻易使用验证码,目前很多网站的做法是如果在短时间内多次提交一个表单未获得成功后才要求提供验证码,这样会获得较好的用户体验。

补充:防火墙的架设是Web安全的重要保障,ModSecurity是开源的Web防火墙中的佼佼者。企业级防火墙的架设应当有两级防火墙,Web服务器和部分应用服务器可以架设在两级防火墙之间的DMZ,而数据和资源服务器应当架设在第二级防火墙之后。

4、什么是跨域如何解决?

JavaScript由于安全性方面的考虑,不允许页面跨域调用其他页面的对象,那么问题来了,什么是跨域问题?

答:这是由于浏览器同源策略的限制,现在所有支持JavaScript的浏览器都使用了这个策略。那么什么是同源呢?所谓的同源是指三个方面“相同”:

  1. 域名相同
  2. 协议相同
  3. 端口相同

下面就举几个例子来帮助更好的理解同源策略。

URL 说明 是否允许通信
http://www.a.com/a.js
http://www.a.com/b.js
同一域名 允许
http://www.a.com/a.js
http://www.b.com/a.js
不同域名 不允许
http://www.a.com:8000/a.js
http://www.a.com/b.js
同一域名不同端口 不允许
https://www.a.com/a.js
http://www.a.com/b.js
同一域名不同协议 不允许

第一种解决办法

1.普通的GET或者POST请求跨域。

      在自己编写的过滤器文件中添加如下代码,也可以再单独的方法中添加,:

      //允许所有的域都可以跨域访问

      response.addHeader("Access-Control-Allow-Origin", "*");

     //允许跨域GET和POST请求

     response.addHeader("Access-Control-Allow-Method", "*");

     //以上两行代码,就可以解决普通的GET和POST请求的跨域问题。

2.ajax的json请求

    //需要添加普通跨域请求的两行代码,然后再添加下面的代码。

    //解决JSON格式的ajax请求,先是 Options请求,这是预检命令,如果预检命令检查通过之后才进行真正的请求。

      response.addHeader("Access-Control-Allow-Headers","Content-Type");

     //缓存预检命令,在规定的时间内不需要重复的进行预检操作。

      response.addHeader("Access-Control-Max-Age","3600");//单位为秒。

3.带有cookie的跨域请求

response.addHeader("Access-Control-Allow-Origin", "http://localhost:8020");//如果是带有cookie的跨域访问,则允许跨域的域名必须准确对应,不可以使用*。也可以通过判断客户端的请求中包含的域名来判断

Stringorigin = request.getHeader(“Origin”);
If(origin!= “”){
   response.addHeader("Access-Control-Allow-Origin",origin);
}

response.addHeader("Access-Control-Allow-Credentials","true");

带有自定义的cookie的跨域请求

需要修改headers的信息。

response.addHeader("Access-Control-Allow-Headers","Content-Type,自定义1,自定义2");

 

第二种解决办法:

通过jsonp跨域请求的方式。JSONP和JSON虽然只有一个字母的区别,但是他们完全就是两回事,很多人很容易把他们搞混。JSON是一种数据交换的格式,而JSONP则是一种非官方跨域数据交互协议

$.ajax({
   url:"your url",
   type:"get or post",
   async:false,
   dataType : "jsonp",
   //服务端用于接收callback调用的function名的参数
   jsonp:"callbackparam",
   //callback的function名称
   jsonpCallback:"success_jsonpCallback",
   success:function(data){
     console.log(data);
   },
   error:function(data){
   console.log(data);
 }
});

这里的callbackparam和success_jsonpCallback可以理解为发送的data数据的键值对,可以自定义,但是callbackparam需要和后台约定好参数名称,因为后台需要获取到这个参数里面的值(即success_jsonpCallback)。

PrintWriter out =null;
String callback=req.getParameter("callbackparam");
String json=callback+"({'status':'ok'})";
try
{
 out = resp.getWriter();
} catch (IOException e)
{
 // TODO Auto-generated catch block
 e.printStackTrace();
}
out.print(json);
out.flush();
out.close();

首先需要获取参数名为callbackparam的值,这里获取到的值就是“success_jsonpCallback”。然后将这个值加上一对小括号。小括号里放入你需要返回的数据内容,比如这里我返回一个JSON对象。当然你也可以返回其他对象,比如只返回一个字符串类型数据也可以。最后前端JS返回的数据就是这样的:

success_jsonpCallback({'status':'ok'})

浏览器会自动解析为json对象,这时候你只需要在success回调函数中直接用data.status就可以了


相关文章
|
3天前
|
Java
【Java多线程】面试常考 —— JUC(java.util.concurrent) 的常见类
【Java多线程】面试常考 —— JUC(java.util.concurrent) 的常见类
13 0
|
3天前
|
安全 Java 程序员
【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)
【Java多线程】面试常考——锁策略、synchronized的锁升级优化过程以及CAS(Compare and swap)
6 0
|
5天前
|
Java
三个可能的Java面试题
Java垃圾回收机制自动管理内存,回收无引用对象的内存,确保内存有效利用。多态性允许父类引用操作不同子类对象,如Animal引用可调用Dog的方法。异常处理机制通过try-catch块捕获和处理程序异常,例如尝试执行可能导致ArithmeticException的代码,catch块则负责处理异常。
28 9
|
16天前
|
Java
【JAVA面试题】static的作用是什么?详细介绍
【JAVA面试题】static的作用是什么?详细介绍
|
16天前
|
Java
【JAVA面试题】final关键字的作用有哪些
【JAVA面试题】final关键字的作用有哪些
|
16天前
|
JavaScript 前端开发 Java
【JAVA面试题】什么是引用传递?什么是值传递?
【JAVA面试题】什么是引用传递?什么是值传递?
|
16天前
|
安全 Java
【JAVA面试题】什么是对象锁?什么是类锁?
【JAVA面试题】什么是对象锁?什么是类锁?
|
16天前
|
存储 自然语言处理 Java
【JAVA面试题】什么是代码单元?什么是码点?
【JAVA面试题】什么是代码单元?什么是码点?
|
3天前
|
Java 数据库
【Java多线程】对线程池的理解并模拟实现线程池
【Java多线程】对线程池的理解并模拟实现线程池
12 1
|
1天前
|
Java
Java一分钟:线程协作:wait(), notify(), notifyAll()
【5月更文挑战第11天】本文介绍了Java多线程编程中的`wait()`, `notify()`, `notifyAll()`方法,它们用于线程间通信和同步。这些方法在`synchronized`代码块中使用,控制线程执行和资源访问。文章讨论了常见问题,如死锁、未捕获异常、同步使用错误及通知错误,并提供了生产者-消费者模型的示例代码,强调理解并正确使用这些方法对实现线程协作的重要性。
9 3