---
title: interview question
date: 2018-07-22 17:18:21
update: 2018-10-07 07:24:00
categories: interview
tags: interview
---
### 接口和抽象类的区别
> 什么是抽象方法
抽象方法就是以abstract修饰的方法,这种方法只声明返回的数据类型,方法名称和所需要的参数,没有方法体,也就是说抽象方法只需要声明而不需要事先,当一个方法为抽象方法时,意味着这个方法必须被子类的方法所重写,否则其子类的该方法仍然是abstract的,而这个子类也必须是抽象的,即声明为abstract
> 区别
接口是特殊的抽象类,自JDK8以来
* 成员变量 -> 接口中成员变量只能是`public static final`类型,抽象类中的成员变量可以是各种类型的。
* 方法 -> 接口中可以有`public abstract抽象方法`、`static方法`、`static代码块`、`default`方法,抽象类中可以有`public abstract抽象方法`、`static方法`、`static代码块`、`一般类型方法`,但是不能有`default`方法。
* 抽象类在可以在非抽象一般方法中提供成员方法的实现细节,而接口中不能存非抽象方法,如不支持`public void a(){}`。
* 一个类只能继承一个抽象类,而一个类只能实现一个或多个接口。
```java
public interface PersonIterface {
/**
* S jdk8之前版本
* interface中只能存在public static final类型的成员变量,和public abstract类型的方法。
* 不能存在static代码块
*/
public static final int field = 0;
// 等价于上一行代码
int field1 = 0;
public abstract void method(int a) throws Exception;
void method1(int a) throws Exception;
/**
* E jdk8之前
*/
/**
* S jdk8以及以后的版本中
* interface中可以定义public static final类型的成员变量,和public abstract类型的方法,新增了static和default方法。
* 不能存在static代码块
* 静态方法,只能通过接口名调用,不可以通过实现类的类名或者实现类的对象调用。default方法,只能通过接口实现类的对象来调用
*/
// static修饰符定义静态方法
static void staticMethod() {
System.out.println("接口中的静态方法");
}
// default修饰符定义默认方法
default void defaultMethod() {
System.out.println("接口中的默认方法");
}
/**
* E jdk8以及以后的版本中
*/
int testa = 2;
public static void main(String[] args) {
}
}
```
```java
/**
*/
public abstract class PersonAbstract {
public static final int field = 0;
// 等价于上一行代码
int field1 = 0;
public abstract void method(int a) throws Exception;
abstract void method1(int a) throws Exception;
static void staticMethod() {
System.out.println("接口中的静态方法");
}
static {
int a = 1;
System.out.println(a);
}
protected void test(){
}
public static void main(String[] args) {
}
}
```

> 接口的作用
- 重要性
在Java语言中, abstract class 和interface 是支持抽象类定义的两种机制。正是由于这两种机制的存在,才赋予了Java强大的 面向对象能力。
- 简单、规范性
如果一个项目比较庞大,那么就需要一个能理清所有业务的架构师来定义一些主要的接口,这些接口不仅告诉开发人员你需要实现那些业务,而且也将命名规范限制住了(防止一些开发人员随便命名导致别的程序员无法看明白)。
- 维护、拓展性
比如你要做一个画板程序,其中里面有一个面板类,主要负责绘画功能,然后你就这样定义了这个类。可是在不久将来,你突然发现这个类满足不了你了,然后你又要重新设计这个类,更糟糕是你可能要放弃这个类,那么其他地方可能有引用他,这样修改起来很麻烦。
如果你一开始定义一个接口,把绘制功能放在接口里,然后定义类时实现这个接口,然后你只要用这个接口去引用实现它的类就行了,以后要换的话只不过是引用另一个类而已,这样就达到维护、拓展的方便性。
- 安全、严密性
接口是实现软件松耦合的重要手段,它描叙了系统对外的所有服务,而不涉及任何具体的实现细节。这样就比较安全、严密一些(一般软件服务商考虑的比较多)。
> 抽象类的作用
- 为子类提供一个公共的类型;
- 封装子类中重复内容(成员变量和方法);
- 定义有抽象方法,子类虽然有不同的实现,但该方法的定义是一致的。
> 接口和抽象类为什么不能实例化对象呢
因为接口和抽象类中都含有抽象方法,这些方法没有具体的实现细节,实例化的接口或抽象对象访问其中的方法没有任何意义。
### JVM加载class文件的原理机制
JVM中类的装载是由ClassLoader和它的子类来实现的,它负责在运行时查找和装入类文件的类。
类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载、链接和初始化,其中链接又可以分成校验、准备、解析装载:查找和导入类或接口的二进制数据(类的编写格式); 链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的; 校验:检查导入类或接口的二进制数据的正确性; 准备:给类的静态变量分配并初始化存储空间; 解析:将符号引用转成直接引用;初始化:激活类的静态变量,初始化Java代码和静态Java代码块
### jvm内存结构

java内存主要分为6部分,分别是程序计数器,虚拟机栈,本地方法栈,堆,方法区和直接内存
1、程序计数器
线程私有,即每个线程都会有一个,线程之间互不影响,独立存储。
代表着当前线程所执行字节码的行号指示器。
2、虚拟机栈
线程私有,它的生命周期和线程相同。
描述的是java方法执行的内存模型:每个方法在执行的同时多会创建一个栈帧用于存储局部变量表、操作数栈、动态链表、方法出口等信息。
每一个方法从调用直至完成的过程,就对应着一个栈帧在虚拟机中入栈到出栈的过程。
局部变量表存放了编译期可知的各种基本数据类型和对象引用,所需内存空间在编译期确定
3、本地方法栈
同虚拟机栈,只不过本地方法栈位虚拟机使用到的native方法服务。
Sun HotSpot虚拟机把本地方法栈和虚拟机栈合二为一。
4、java堆
线程共享
主要用于分配对象实例和数组。
5、方法区
线程共享
用于存储已被虚拟机加载的类8息、常量、静态变量、即使编译后的代码等数据。
6、直接内存
直接内存并不是虚拟机运行时数据区的一部分。
总结:
大多数 JVM 将内存区域划分为 Method Area(Non-Heap)(方法区) ,Heap(堆) , Program Counter Register(程序计数器) , VM Stack(虚拟机栈,也有翻译成JAVA 方法栈的),Native Method Stack ( 本地方法栈 ),其中Method Area 和 Heap 是线程共享的 ,VM Stack,Native Method Stack 和Program Counter Register 是非线程共享的。为什么分为 线程共享和非线程共享的呢?请继续往下看。
首先我们熟悉一下一个一般性的 Java 程序的工作过程。一个 Java 源程序文件,会被编译为字节码文件(以 class 为扩展名),每个java程序都需要运行在自己的JVM上,然后告知 JVM 程序的运行入口,再被 JVM 通过字节码解释器加载运行。那么程序开始运行后,都是如何涉及到各内存区域的呢?
概括地说来,JVM初始运行的时候都会分配好 Method Area(方法区) 和Heap(堆) ,而JVM 每遇到一个线程,就为其分配一个 Program Counter Register(程序计数器) , VM Stack(虚拟机栈)和Native Method Stack (本地方法栈), 当线程终止时,三者(虚拟机栈,本地方法栈和程序计数器)所占用的内存空间也会被释放掉。这也是为什么我把内存区域分为线程共享和非线程共享的原因,非线程共享的那三个区域的生命周期与所属线程相同,而线程共享的区域与JAVA程序运行的生命周期相同,所以这也是系统垃圾回收的场所只发生在线程共享的区域(实际上对大部分虚拟机来说知发生在Heap上)的原因。
方法区用于存储JVM加载的类信息、常量、静态变量、即使编译器编译后的代码等数据,是线程隔离的(错误)
解析:方法区 和堆都是线程共享的。
### UseCompressedOops有什么作用为什么要使用
当你将你的应用从 32 位的 JVM 迁移到 64 位的 JVM 时,由于对象的指针从 32 位增加到了 64 位,因此堆内存会突然增加,差不多要翻倍。这也会对 CPU 缓存(容量比内存小很多)的数据产生不利的影响。因为,迁移到 64 位的 JVM 主要动机在于可以指定最大堆大小,通过压缩 OOP 可以节省一定的内存。通过 -XX:+UseCompressedOops 选项,JVM 会使用 32 位的 OOP,而不是 64 位的 OOP。
### 怎样通过Java程序来判断JVM是32位还是64位
你可以检查某些系统属性如 sun.arch.data.model 或 os.arch 来获取该信息。
### instanceofjava关键字
你在面月薪6000-8000的Java研发职位。面试官也知道JVM这么个大体概念,但知道的也不多。JVM这个概念本身就是“底层”。JVM有一条名为 instanceof 的指令,而Java源码编译到Class文件时会把Java语言中的 instanceof 运算符映射到JVM的 instanceof 指令上。
1. instanceof 是javac能识别的一个关键字,对应到Token.INSTANCEOF的token类型。做词法分析的时候扫描到"instanceof"关键字就映射到了一个Token.INSTANCEOF token。jdk7u/jdk7u/langtools: 5c9759e0d341 src/share/classes/com/sun/tools/javac/parser/Token.java
2. 该编译器的抽象语法树节点有一个JCTree.JCInstanceOf类用于表示instanceof运算。做语法分析的时候解析到instanceof运算符就会生成这个JCTree.JCInstanceof类型的节点。jdk7u/jdk7u/langtools: 5c9759e0d341 src/share/classes/com/sun/tools/javac/parser/JavacParser.java term2Rest()
3. 中途还得根据Java语言规范对instanceof运算符的编译时检查的规定把有问题的情况找出来。
4. 到最后生成字节码的时候为JCTree.JCInstanceof节点生成instanceof字节码指令。jdk7u/jdk7u/langtools: 5c9759e0d341 src/share/classes/com/sun/tools/javac/jvm/Gen.java visitTypeTest()
### 堆和栈的区别
1. 栈是存储局部变量,基本数据和方法调用。
堆内存是存储Java中的对象。运行时期产生的而对象和数据会在堆中分配空间。是gc管理的最大的区域
2. 如果栈内存没有可用的空间存储方法调用和局部变量,JVM会抛出java.lang.StackOverFlowError。
而如果是堆内存没有可用的空间存储生成的对象,JVM会抛出java.lang.OutOfMemoryError。
3. Java的堆是一个运行时数据区,堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的。Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
4. 栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。例如编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。
5. 栈中的数据共享的区别,和两个对象引用同时执行同一个堆中对象是不同的。通过一个对象的引用改变对象的数据,那么另一个对象的引用所指向的堆中的对象数据也会改变。而在栈中int a = 1;int b = 1; a改变不会影响吧的值。
### Class.forName的作用
调用该访问返回一个类名为指定字符串的类的对象。
### JSP4种域对象的查找方式
${pageScope .username} 作用范围: 当前页面
${requestScope.username} 作用范围:当前请求
${sessionScope.username} 作用范围:当前会话
${applicationScope.username} 作用范围:当前应用
### JSP的九大内置对象
| 名称 | 类 | 作用域 |
| :------ | :------ | :------ |
| request请求对象 | java.servlet.ServletRequest(接口)HttpServletRequest(实现类) | Request |
| response响应对象| javax.servlet.SrvletResponse(接口)HttpServletResponse(实现类) | Page |
| pageContext页面上下文对象 | javax.servlet.jsp.PageContext(实现类) | Page |
| session会话对象 | javax.servlet.http.HttpSession(接口)实现类(tomcat) | Session |
| application应用程序对象 | javax.servlet.ServletContext(接口)实现类(Tomcat中的实现类是ApplicationContext) | Application |
| out输出对象 | javax.servlet.jsp.JspWriter | Page |
| config配置对象 | javax.servlet.ServletConfig(在Tomcat中的实现类是StandardWrapper) | Page |
| page页面对象 | javax.lang.Object | Page |
| exception例外对象 | javax.lang.Throwable | Page |
总结
ServletConfig在Tomcat中的实现类是StandardWrapper
ServletContext在Tomcat中的实现类是ApplicationContext
Servlet能获取到的ServletConfig和ServletContext是StandardWrapper和ApplicationContext的Facade类
Facade是一种设计模式,作用是只开放部分的内容给使用者,详细请搜索Facade设计模式
### 什么是js
JavaScript 是属于网络的脚本语言!
JavaScript 被数百万计的网页用来改进设计、验证表单、检测浏览器、创建cookies,以及更多的应用。
JavaScript 是因特网上最流行的脚本语言。
JavaScript 很容易使用!你一定会喜欢它的!
### js的4种对象
js 中的内部对象包括Array、Boolean、Date、Function、Global、Math、Number、Object、RegExp、 String以及各种错误类对象,包括Error、EvalError、RangeError、ReferenceError、SyntaxError和 TypeError。
其中Global和Math这两个对象又被称为“内置对象”,这两个对象在脚本程序初始化时被创建,不必实例化这两个对象。
#### 内置对象
Number
JavaScript Number 对象是 一个数值包装器。您可以将其与 new 关键词结合使用,并将其设置为一个稍后要在 JavaScript 代码中使用的变量:
var myNumber = new Number(numeric value);
Boolean
Boolean 在尝试 用 JavaScript 创建任何逻辑时是必要的。Boolean 是一个 代表 true 或 false 值的对象。 Boolean 对象有多个值,这些值 相当于 false 值(0、 -0、null 或 "" [一个空字串]),未定义的 (NaN),当然还有 false。所有其他布尔 值相当于 true 值。该对象可以 通过 new 关键词进行实例化,但通常是 一个被设为 true 或 false 值的变量:
var myBoolean = true;
String
JavaScript String 对象是 文本值的包装器。除了存储文本, String 对象包含一个属性和各种 方法来操作或收集有关文本的信息。与 Boolean 对象类似, String 对象不需要进行实例化 便能够使用。例如,您可以将一个变量设置为一个字符串, 然后 String 对象的所有属性或 方法都可用于该变量:
var myString = "My string";
Date
JavaScript Date 对象提供了一种方式 来处理日期和时间。您可以用许多不同的 方式对其进行实例化,具体取决于想要的结果。例如,您可以在没有参数的情况下对其进行实例化:
var myDate = new Date();
//或传递 milliseconds 作为一个参数:
var myDate = new Date(milliseconds);
//您可以将一个日期字符串作为一个参数传递:
var myDate = new Date(dateString);
//或者您可以传递多个参数来创建一个完整的日期:
var myDate = new Date(year, month, day, hours, minutes, seconds, milliseconds);
Array
JavaScript Array 对象是一个存储变量的变量:您可以用它一次在一个变量中存储多个值, 它有许多方法允许您操作或收集 有关它所存储的值的信息。尽管 Array 对象不差别对待值类型,但是 在一个单一数组中使用同类值是很好的做法。因此, 在同一数组中使用数字和字符串不是好的做法。所有 可用于 Array 对象的属性 都是只读的,这意味着它们的值不能从外部予以更改。
可用于 Array 对象的惟一属性 是 length。该属性返回 一个数组中的元素数目,通常在使用 循环迭代数组中的值时用到:
var myArray = new Array(1, 2, 3);
for(var i=0; i ");
document.write("姓名:" + s.name + "
"); document.write("薪水:" + s.sal + "
"); ``` #### 浏览器对象 window,document,status,location,history… ```javascript function myrefresh(){ window.history.go(0); } ``` #### ActiveX对象 ActiveXObject("Microsoft.XMLHTTP")… ### 初始化js函数方式 1 浏览器对象调用 ```javascript window.onload=function(){ alert(0); //var inputs = document.getElementsByTagName("input"); //alert(inputs); } ``` 2 jquery对象调用 ```javascript $(function(){ alert(0); }) ``` 3 写到标签中 ```javascript ``` ### javascript中获取标签元素的方式有哪些 #### getElementById document.getElementById('demo') //demo是元素对应的ID #### getElementsByTagName document.getElementsByTagname('li') //li是标签的名字 需要注意的是,该方法除了能被document对象调用之外,还可以被普通的元素调用。示例如下: var demo = document.getElementById('demo'); var lis = demo.getElementsByTagname('li'); #### getElementsByClassName 除了通过指定标签获取元素外,DOM还提供了getElementsByClassName方法来获取指定class名的元素。不过由于该方法比较新,较老的浏览器还不支持,比如IE6。不过我们可以通过hack方式来弥补老浏览器缺陷。该方法调用的方式如下所示: document.getElementsByClassName('demo') //demo为元素指定的class名 和getElementsByTagname一样, 该方法除了能被document对象调用之外,还可以被普通的元素调用。 对于比较老的浏览器,比如IE6、7我们可以通过下面的hack方式来实现: ```javascript function getElementsByClassName(node,classname){ if(node.getElementsByClassName) { return node.getElementsByClassName(classname); }else { var results = []; var elems = node.getElementsByTagName("*"); for(var i = 0; i < elems.length; i++){ if(elems[i].className.indexOf(classname) != -1){ results[results.length] = elems[i]; } } return results; } } ``` ### js中操作标签的class属性的关键字是什么 JavaScript中使用e.getAttribute('属性名')来取得属性的值,并且用e.setAttribute('属性名', '值')来设置属性值。 由于class属于JavaScript保留值,因此当我们要操作元素的class属性值时,直接使用e.getAttribute('class')和e.setAttribute('class', 'value')可能会遭遇浏览器兼容性问题 以下列表说明了上文提及的三种做法的浏览器兼容性测试: • e.className 能在IE、Mozilla(Firefox)、Opera和Safari正确运行 • e.getAttribute('class')和e.setAttribute('class', 'value') 能在Mozilla(Firefox)和Opera中正确运行,在IE和Safari中则不能使用。 • e.getAttribute('className') 在IE和Opera中正确运行,在Mozilla(Firefox)和Safari中则不能使用。 ### 写出JavaScript后退到前一个页面的操作,与在浏览器上点击后退按钮相同 ```html第一个页面
下一个页面 ``` ```html第二个页面
``` ### ajax AJAX 是 Asynchronous JavaScript And XML 的首字母缩写。 AJAX 并不是一种新的编程语言,而仅仅是一种新的技术,它可以创建更好、更快且交互性更强的 web 应用程序。 AJAX 使用 JavaScript 在 web 浏览器与 web 服务器之间来发送和接收数据。 通过在幕后与 web 服务器交换数据,而不是每当用户作出改变时重载整个 web 页面,AJAX 技术可以使网页更迅速地响应。 ### servlet返回字符串到页面获取字符串 在一个servlet中: ```java response.setContentType("text/html;charset=UTF-8"); PrintWriter pw = response.getWriter(); pw.write(tip);//写出到浏览器 pw.flush(); pw.close(); ``` ### ajax发送post请求 现有请求地址/getData,请求参数为id,参数值为1,请用jQuery通过Ajax发送POST请求,获取json数据,打印到控制台 action类 ```java import javax.servlet.http.HttpServletRequest; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class GetDataAction extends ActionSupport{ private User user; public String getData(){//不能传参 HttpServletRequest request = ServletActionContext.getRequest(); System.out.println("进入action"); String id = request.getParameter("id"); user = new User(); user.setId(id); user.setUserName("张三"); System.out.println(user); return SUCCESS; } public User getUser() { return user; } } ``` jsp页面 ```html <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>获取json对象
```
### XML与json
xml扩展标记语言 (Extensible Markup Language, XML) ,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 XML使用DTD(document type definition)文档类型定义来组织数据;格式统一,跨平台和语言,早已成为业界公认的标准。
XML是标准通用标记语言 (SGML) 的子集,非常适合 Web 传输。XML 提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。++++++++++++++++++++++++++++++++++
JSON(JavaScript Object Notation)一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性。可在不同平台之间进行数据交换。JSON采用兼容性很高的、完全独立于语言文本格式,同时也具备类似于C语言的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)体系的行为。这些特性使JSON成为理想的数据交换语言。
JSON基于JavaScript Programming Language , Standard ECMA-262 3rd Edition - December 1999 的一个子集。
XML的优点
A.格式统一,符合标准;
B.容易与其他系统进行远程交互,数据共享比较方便。
XML的缺点
A.XML文件庞大,文件格式复杂,传输占带宽;
B.服务器端和客户端都需要花费大量代码来解析XML,导致服务器端和客户端代码变得异常复杂且不易维护;
C.客户端不同浏览器之间解析XML的方式不一致,需要重复编写很多代码;
D.服务器端和客户端解析XML花费较多的资源和时间。
JSON的优点:
A.数据格式比较简单,易于读写,格式都是压缩的,占用带宽小;
B.易于解析,客户端JavaScript可以简单的通过eval()进行JSON数据的读取;
C.支持多种语言,包括ActionScript, C, C#, ColdFusion, Java, JavaScript, Perl, PHP, Python, Ruby等服务器端语言,便于服务器端的解析;
D.在PHP世界,已经有PHP-JSON和JSON-PHP出现了,偏于PHP序列化后的程序直接调用,PHP服务器端的对象、数组等能直接生成JSON格式,便于客户端的访问提取;
E.因为JSON格式能直接为服务器端代码使用,大大简化了服务器端和客户端的代码开发量,且完成任务不变,并且易于维护。
JSON的缺点
A.没有XML格式这么推广的深入人心和喜用广泛,没有XML那么通用性;
B.JSON格式目前在Web Service中推广还属于初级阶段。
### HTML加载顺序
```html
```
从上到下运行,先解析head标签中的代码,
(1)head标签中会包含一些引用外部文件的代码,从开始运行就会下载这些被引用的外部文件
当遇到script标签的时候浏览器暂停解析(不是暂停下载),将控制权交给JavaScript引擎(解释器)
如果`
```
```html
/jsp/success.jsp
/jsp/getdatabypost.jsp
```
异步发布信息
```
//异步发布信息,无需返回值
public void publicInfo(){
try {
if(info != null){
//1、更新信息状态
Info tem = infoService.findObjectById(info.getInfoId());
tem.setState(info.getState());
infoService.update(tem);
//2、输出更新结果
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("text/html");
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write("更新状态成功".getBytes("utf-8"));
outputStream.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
```
listUI.JSP
```
//异步发布信息,信息的id及将要改成的信息状态
function doPublic(infoId, state){
//1、更新信息状态
$.ajax({
url:"${basePath}nsfw/info_publicInfo.action",
data:{"info.infoId":infoId, "info.state":state},
type:"post",
success: function(msg){
//2、更新状态栏、操作栏的显示值
if("更新状态成功" == msg){
if(state == 1){//说明信息状态已经被改成 发布,状态栏显示 发布,操作栏显示 停用
$("#show_"+infoId).html("发布");
$("#oper_"+infoId).html('停用');
} else {
$("#show_"+infoId).html("停用");
$("#oper_"+infoId).html('发布');
}
} else {alert("更新信息状态失败!");}
},
error: function(){
alert("更新信息状态失败!");
}
});
```
### springmvc的工作流程


Spring工作流程描述
1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;
2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping(映射器)获得该Handler配置的所有相关的对象(包括Handler对象以及(加载controllerRequestMapping注解信息)Handler对象对应的拦截器),最后以HandlerExecutionChain(执行链)对象的形式返回,把handler交给核心控制器;
3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter(适配器)。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法)
4. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
5. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
6. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;
7. ViewResolver 结合Model和View,来渲染视图
8. 将渲染结果返回给客户端。
其他流程图解

(1).发起请求到前端控制器(DispatcherServlet);
(2).前端控制器请求HandlerMapping查找Handler,可以根据xml配置、注解进行查找;
(3).处理器映射器HandlerMapping向前端控制器返回Handler;
(4).前端控制器调用处理器适配器去执行Handler(包含的controller注解的信息);
(5).处理器适配器去执行Handler;
(6).Handler执行完成给适配器返回ModelAndView;
(7).处理器适配器向前端控制器返回ModelAndView(是springmvc框架的一个底层对象,包括Model和View);
(8).前端控制器请求视图解析器去进行视图解析,根据逻辑视图名称解析真正的视图(jsp...);
(9).视图解析器向前端控制器返回View;
(10).前端控制器进行视图渲染,视图渲染就是将模型数据(在ModelAndView对象中)填充到request域中。
(11).前端控制器向用户响应结果。
面试回答的流程:
1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;
2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping(映射器)获得该Handler配置的所有相关的对象(包括Handler对象以及加载controllerRequestMapping注解信息),最后以HandlerExecutionChain(执行链)对象的形式返回,把handler交给核心控制器。
3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter(适配器),并获取适配器。
4. DispatcherServlet 调用适配器去执行Handler(包含的controller注解的信息);
5. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象(向视图发送的数据和视图的逻辑名字);
6. DispatcherServlet根据返回的ModelAndView,选择一个适合的ViewResolver(视图解析器)返回给DispatcherServlet ;
7. DispatcherServlet请求视图解析器去进行视图解析,根据逻辑视图名称解析真正的视图(jsp...)。返回一个View给DispatcherServlet。
8. 前端控制器进行视图渲染,视图渲染就是将模型数据(在ModelAndView对象中)填充到request域中。
9. 前端控制器向用户响应结果。
Spring工作流程描述
为什么Spring只使用一个Servlet(DispatcherServlet)来处理所有请求?
详细见J2EE设计模式-前端控制模式
Spring为什么要结合使用HandlerMapping以及HandlerAdapter来处理Handler?
符合面向对象中的单一职责原则,代码架构清晰,便于维护,最重要的是代码可复用性高。如HandlerAdapter可能会被用于处理多种Handler。
1.客户端发送请求,符合.action的话,就有dispatchservlet来处理
1.1.交给映射器,交给action处理
2.映射器根据客户的http请求,在对比如果匹配正确,再讲http请求交给
3.执行Action中的业务方法,最总发挥一个名叫ModelAndView的对象,其中封装了,向视图发送的数据和视图的逻辑名字。
4.ModelAndView对象随着响应到达核心dispatchservlet中
5.这时DispatcherServlet收到这个对象,它也不知道视图逻辑名是何意,有的未退一个名叫视图解析器对象,具体解析modelandview中的内容。
6.将试图解析后的内容交给dispatchservlet核心控制器对象,进行视图渲染,将数据填充到request与对象中,请求转发到具体的视图页面。取出数据进行再显示给用户。



优点:
1. 提供了一种管理对象的方法,可以把中间层对象有效地组织起来。一个完美的框架“黏合剂”。
2. 采用了分层结构,可以增量引入到项目中。
3. 有利于面向接口编程习惯的养成。
4. 目的之一是为了写出易于测试的代码。
5. 非侵入性,应用程序对Spring API的依赖可以减至最小限度。
6. 一致的数据访问介面。
缺点:
1,Spring的使用引入了新的复杂度,这点毋庸置疑(虽然可降低已有复杂度,但是小型项目引入Spring简直是噩梦)。
小型项目必需要使用spring吗? 其实也不能论大小来说,当你想要方便地使用某些特性的时候,比如说ioc,切面,声明式事务等等,那就应该用spring,你都需要那么多spring能轻易集成并且串联的功能,为什么还要不使用spring呢?
当然如果项目用不上这些特性,也没说一定要用spring。
2,破坏了一些本来不该破坏的结构,比如一个类的完整抽象,现在需要通过看配置文件或Annotation才能完全理解,
这是ioc容器共有的特征,当然,一个好的ide,比如IntelliJ IDEA 在:重构、导航方面,你几乎不会感觉到因为使用ioc而带来的不便。
3,单个功能的测试必须启动Spring容器。
启动慢了点,不过在编码上用Spring JUnit Runner注解也不会多敲多少代码
spring和springmvc中的配置
spring
加载applicationContext.xml方法(应用上下文配置)
```
org.springframework.web.context.ContextLoaderListener
contextConfigLocation
classpath:applicationContext.xml
```
applicationContext.xml
```
```
springmvc配置
spring.xml
```
```
需要配置web.xml中核心过滤器(servlet)
```
DispatcherServlet
org.springframework.web.servlet.DispatcherServlet
ContextConfigLocation
classpath:spring.xml
DispatcherServlet
*.action
helloSpringMVCzhujie2
index.html
index.htm
index.jsp
default.html
default.htm
default.jsp
```
视图解析器InternalResourceViewResolver【解析视图逻辑名对应的真实路径】
ModelAndView对象中即可以封装真实视图路径名,也可以封装视图路径的逻辑名,springmvc.xml
代码如下:
```
```
Action类代码如下:
modelAndView.setViewName("success");
映射器Mapping【什么样的请求交给Action】
1) org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping(核心)
将程序员定义的Action所对应的标签的name属性作为请求路径
```
```
2) org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
/delete.action和/update.action和/find.action请求路径都交由标签为id的Action,即
多个路径对应同一个Action
```
userActionID
userActionID
userActionID
```
适配器Adapter【Action实现什么接口】
1) Action实现Controller接口
```
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
public class EmpAction implements Controller{
public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws Exception {
System.out.println("EmpAction::handleRequest");
request.setCharacterEncoding("UTF-8");
String username = request.getParameter("username");
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("message",username);
modelAndView.setViewName("/jsp/success.jsp");
return modelAndView;
```
控制器Controller【Action继承什么类】
1.org.springframework.web.servlet.mvc.ParameterizableViewController
如果请求是/hello.action的请求路径,则直接跳转到/jsp/success.jsp页面,
不经过程序员定义的控制器Action
```
```
2. org.springframework.web.servlet.mvc.AbstractCommandController
能够以实体的形式,收集客户端参数
```
public class AdminAction extends AbstractCommandController{
public AdminAction(){
this.setCommandClass(Admin.class);
}
@Override
protected ModelAndView handle(HttpServletRequest request,HttpServletResponse response, Object obj, BindException bindException)throws Exception {
System.out.println("AdminAction::handle");
ModelAndView modelAndView = new ModelAndView();
Admin admin = null;
if(obj instanceof Admin){
admin = (Admin) obj;
}
modelAndView.addObject("username",admin.getUsername());
modelAndView.addObject("gender",admin.getGender());
modelAndView.addObject("hiredate",admin.getHiredate());
modelAndView.setViewName("/jsp/success.jsp");
return modelAndView;
}
}
```
```
```
spring-mvc中json格式对象数据传输
```
@RequestMapping("/doAjax")
@ResponseBody //如果返回json格式,需要这个注解,这里用来测试环境
public Object doAjax(Supplier supplier){
System.out.println("---doAjax.supplier:"+supplier);
supplier.setSupName("supName1");
return supplier;
}
```
在spring.xml中配置
```
```
struts与json数据省份-城市-区域三级联动【Struts2 + JSON版】
action
```
/**
* 根据省份查询城市
*/
public String findCityByProvinceMethod() throws Exception{
cityList = new ArrayList();
if("湖北".equals(province)){
cityList.add("武汉");
cityList.add("黄岗");
}else if("湖南".equals(province)){
cityList.add("岳阳");
cityList.add("张家界");
}else if("广东".equals(province)){
cityList.add("韶关");
cityList.add("东莞");
}
return "ok";
}
/**
* 根据城市查询区域
*/
public String findAreaByCityMethod() throws Exception{
areaList = new ArrayList();
if("武汉".equals(city)){
areaList.add("AA");
areaList.add("BB");
}else if("黄岗".equals(city)){
areaList.add("CC");
areaList.add("DD");
}else if("岳阳".equals(city)){
areaList.add("EE");
areaList.add("FF");
}else if("张家界".equals(city)){
areaList.add("GG");
areaList.add("HH");
}else if("韶关".equals(city)){
areaList.add("II");
areaList.add("JJ");
}else if("东莞".equals(city)){
areaList.add("KK");
areaList.add("LL");
}
return "ok";
}
private List cityList;
private List areaList;
public List getCityList() {//json与struts结合使用需要提供get方法
return cityList;
}
public List getAreaList() {
return areaList;
}
```
struts.xml
```
```
导包:struts2-json-plugin-2.3.1.1.jar
javabean2json
使用第三方工具,将JavaBean对象/List或Set或Map对象转成JSON
准备导入第三方jar包:
》commons-beanutils-1.7.0.jar
》commons-collections-3.1.jar
》commons-lang-2.5.jar
》commons-logging-1.1.1.jar
》ezmorph-1.0.3.jar
》json-lib-2.1-jdk15.jar
(1)JavaBean----->JSON
》JSONArray jsonArray = JSONArray.fromObject(city);
》String jsonJAVA = jsonArray.toString();
(2)List----->JSON
》JSONArray jsonArray = JSONArray.fromObject(cityList);
》String jsonJAVA = jsonArray.toString();
(3)List----->JSON
》JSONArray jsonArray = JSONArray.fromObject(stringList);
》String jsonJAVA = jsonArray.toString();
(4)Set----->JSON
》JSONArray jsonArray = JSONArray.fromObject(citySet);
》String jsonJAVA = jsonArray.toString();
(5)Map----->JSON
》JSONArray jsonArray = JSONArray.fromObject(map);
》String jsonJAVA = jsonArray.toString();
最后一个例子切记,将来jQuery-EasyUI-DataGrid组件时我们还要用到
将来,在企业中,就算脱离struts2的环境,也能用第三方工具,将Java类型转成JSON文本
### 介绍一下Spring的事务管理
事务管理对于企业应用而言至关重要。它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性。就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作过程中机器突然出故障的情况,此时,事务就必须确保出故障前对账户的操作不生效,就像用户刚才完全没有使用过取款机一样,以保证用户和银行的利益都不受损失。
编程式事务控制
比较灵活,但开发起来比较繁琐: 每次都要开启、提交、回滚
声明式事务控制
spring声明式事务管理,核心实现就是基于Aop
### springmvc与struts2的区别
1)springmvc的入口是一个servlet,即前端控制器,例如:*.action
struts2入口是一个filter过虑器,即前端过滤器,例如:/*
2)springmvc是基于方法开发,传递参数是通过方法形参,可以设计为单例
struts2是基于类开发,传递参数是通过类的属性,只能设计为多例
3)springmvc通过参数解析器是将request对象内容进行解析成方法形参,将响应数据和页面封装成
ModelAndView对象,最后又将模型数据通过request对象传输到页面
struts采用值栈存储请求和响应的数据,通过OGNL存取数据
### Spring的安全(线程安全?)问题?
Spring框架里的bean,或者说组件,获取实例的时候都是默认的单例模式,这是在多线程开发的时候要尤其注意的地方
Spring利用ThreadLocal解决线程安全问题
我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder)中非线程安全的“状态性对象”采用ThreadLocal进行封装,让它们也成为线程安全的“状态性对象”,因为有状态的Bean就能够以singleton方式在多线程中正常工作了。
### xml配置与注解的优缺点
xml配置文件方式优点:
1、降低耦合,使容易扩展。
2、对象之间的关系一目了然。
3、xml配置文件比注解功能齐全。
xml配置文件方式缺点:
1、配置文件配置工作量相对注解要大。
注解方式优点:
1、在class文件中,可以降低维护成本
2、提高开发效率。
注解方式缺点:
1、如果对annotation进行修改,需要重新编译整个工程。
2、业务类之间的关系不如XML配置那样一目了然。
3、程序中过多的annotation,对于代码的简洁度有一定影响。
4、annotation貌似功能没有xml配置文件齐全
### mybatis工作流程
```
Reader reader = Resources.getResourceAsReader("mybatis.xml");//configraution.config也可以
```
1)通过Reader对象读取src目录下的mybatis.xml配置文件(该文本的位置和名字可任意)
2)通过SqlSessionFactoryBuilder对象创建SqlSessionFactory对象
```
Reader reader = Resources.getResourceAsReader("mybatis.xml");//configraution.config也可以
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
```
3)从当前线程中获取SqlSession对象
4)事务开始,在mybatis中默认
5)通过SqlSession对象读取StudentMapper.xml映射文件中的操作编号,从而读取sql语句
6)事务提交,必写
7)关闭SqlSession对象,并且分开当前线程与SqlSession对象,让GC尽早回收
scm32在事务管理中注入了datasource
优点:
1. 配置generatorConfig.xml可以逆向生成entity实体文件,和相应的entityMapper.xml文件
2. 易于上手和掌握。
3. sql写在xml里,便于统一管理和优化。
4. 解除sql与程序代码的耦合。
5. 提供映射标签,支持对象与数据库的orm字段关系映射
6. 提供对象关系映射标签,支持对象关系组建维护
7. 提供xml标签,支持编写动态sql。
scm32项目的application配置
```
```
缺点:
1. sql工作量很大,尤其是字段多、关联表多时,更是如此。
2. sql依赖于数据库,导致数据库移植性差。
3. 由于xml里标签id必须唯一,导致DAO中方法不支持方法重载。
4. 字段映射标签和对象关系映射标签仅仅是对映射关系的描述,具体实现仍然依赖于sql。(比如配置了一对多Collection标签,如果sql里没有join子表或查询子表的话,查询后返回的对象是不具备对象关系的,即Collection的对象为null)
5. DAO层过于简单,对象组装的工作量较大。
6. 不支持级联更新、级联删除。
7. 编写动态sql时,不方便调试,尤其逻辑复杂时。
8 提供的写动态sql的xml标签功能简单(连struts都比不上),编写动态sql仍然受限,且可读性低。
9. 若不查询主键字段,容易造成查询出的对象有“覆盖”现象。
10. 参数的数据类型支持不完善。(如参数为Date类型时,容易报没有get、set方法,需在参数上加@param)
11. 多参数时,使用不方便,功能不够强大。(目前支持的方法有map、对象、注解@param以及默认采用012索引位的方式)
12. 缓存使用不当,容易产生脏数据。
mybatis配置文件
mybatis.xml
```
CourseMapper.xml
```
StudentMapper.xml
```
```
### 请你谈谈SSH整合
SSH:
Struts(表示层)+Spring(业务层)+Hibernate(持久层)
Struts:
Struts是一个表示层框架,主要作用是界面展示,接收请求,分发请求。
在MVC框架中,Struts属于VC层次,负责界面表现,负责MVC关系的分发。(View:沿用JSP,HTTP,Form,Tag,Resourse ;Controller:ActionServlet,struts-config.xml,Action)
Hibernate:
Hibernate是一个持久层框架,它只负责与关系数据库的操作。
Spring:
Spring是一个业务层框架,是一个整合的框架,能够很好地黏合表示层与持久层。
### webservice
#### 网络七层协议
OSI是一个开放性的通信系统互连参考模型,他是一个定义的非常好的协议规范。OSI模型有7层结构,每层都可以有几个子层。 OSI的7层从上到下分别是 7 应用层 6 表示层 5 会话层 4 传输层 3 网络层 2 数据链路层 1 物理层 其中高层,即7、6、5、4层定义了应用程序的功能,下面3层,即3、2、1层主要面向通过网络的端到端的数据流。
#### 为什么要分层
为了为了简化网络设计的复杂性,通信协议采用分层的结构,各层协议之间既相互独立又相互高效的协调工作。对于复杂的通信协议,其结构应该是采用层次的。分层的协议可以带来很多便利:
分层的好处有:
一 灵活性好:当任何一层发生变化时,只要层间接口关系保持不变,则在这层以上或以下各层均不受影响。此外,对某一层提供的服务还可进行修改。当某层提供的服务不再需要时,甚至可以将这层取消,更容易管理。
二各层之间是独立的:在各层间标准化接口,允许不同的产品只提供各层功能的一部分,某一层不需要知道它的下一层是如何实现的,而仅仅需要知道该层通过层间的接口所提供的服务。由于每一层只实现一种相对独立的功能,所以比较容易实现!
Socket就是为网络服务提供的一种机制。
数据在两个Socket间通过IO传输。
OSI的七层模型 : 物理层、数据链路层、网络层、传输层、表示层、会话层、应用层
- Socket访问 : Socket属于传输层,它是对Tcp/ip协议的实现,包含TCP/UDP,它是所有通信协议
的基础,Http协议需要Socket支持,以Socket作为基础
socket特点:
1. 开启端口,该通信是 长连接的通信 ,很容易被防火墙拦截,可以通过心跳机制
来实现 ,开发难度片段
2. 传输的数据一般是字符串 ,可读性不强
lj|16|1|60|up
3. socket端口不便于推广
http:17.23.23.2:2345 www.jd.com www.360buy.com
4. 性能相对于其他的通信协议是最优的
- Http协议访问 :属于应用层的协议,对Socket进行了封装
1. 跨平台
2. 传数据不够友好 :
get请求: http://127.0.0.1:8888?username=lj&pwd=1234
3. 对第三方应用提供的服务,希望对外暴露服务接口
http:属于应用层的协议,对Socket进行了封装
1. 跨平台
2. 传数据不够友好 :
get请求: http://127.0.0.1:8888?username=lj&pwd=1234
3. 对第三方应用提供的服务,希望对外暴露服务接口
问题:
1. 数据封装不够友好 :可以用xml封装数据
2. 希望给第三方应用提供web方式的服务 (http + xml) = web Service
### WebService概念介绍
1.Web Service
能使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件, 就可相互交换数据或集成。依据Web Service规范实施的应用之间, 无论它们所使用的语言、 平台或内部协议是什么, 都可以相互交换数据
通俗的讲,Web Service就是一个部署在Web服务器上的一个应用,它向外界暴露出一个能够通过Web进行调用的API。这就是说,你能够用编程的方法通过Web来调用这个应用程序。我们把调用这个Web Service 的应用程序叫做客户端,发布这个web服务的应用程序器称为Web Service服务器
2.webservice的规则
- xml
- soap :(simple object access 协议) :简单对象访问协议,比http协议方法速度慢
- wsdl : webservice描述语言 ,它也是xml实现的
通过get或post调用第三方发的webservice服务
```
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
/**调用第三方的webservice服务 ,获取电话号码信息
*
* @author 李俊 2015年5月16日
*/
public class MobileCodeService {
//1. http-get方式访问webservice
public void get(String mobileCode ,String userID ) throws Exception{
/*
* HTTP请求由三部分组成:请求行,请求头,请求正文
* 请求行:请求方法 url/http版本
* url:
* 资源路径路径:/WebServices/MobileCodeWS.asmx/getMobileCodeInfo?mobileCode=string&userID=string
* 主机ip: ws.webxml.com.cn(主机的IP地址)
*/
URL url=new URL("http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx/getMobileCodeInfo?mobileCode="+mobileCode+
"&userID="+userID);
//开启连接
HttpURLConnection conn=(HttpURLConnection) url.openConnection();
//延迟时间
conn.setConnectTimeout(5000);
//请求方法
conn.setRequestMethod("GET");
//响应码
if(conn.getResponseCode()==HttpURLConnection.HTTP_OK){ //获取并判断相应结果码是否为200,成功响应了以后才能获取返回的数据
InputStream is=conn.getInputStream();
//写出到内存的流 ,将流对象写出到内存中
ByteArrayOutputStream boas=new ByteArrayOutputStream();
byte[] buffer=new byte[1024];
int len=-1;
while((len=is.read(buffer))!=-1){//输入流开始读到buffer中,每一次读取判断并判断是否读到了内容
boas.write(buffer, 0, len);
}
System.out.println("GET请求获取的数据:"+boas.toString());
boas.close();
is.close();
}
}
//2.Post请求 :通过Http-Client 框架来模拟实现 Http请求
public void post(String mobileCode ,String userID) throws Exception{
/**HttpClient访问网络的实现步骤:
* 1. 准备一个请求客户端:浏览器
* 2. 准备请求方式: GET 、POST
* 3. 设置要传递的参数
* 4.执行请求
* 5. 获取结果
*/
HttpClient client=new HttpClient();
PostMethod postMethod=new PostMethod("http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx/getMobileCodeInfo");
//3.设置请求参数
postMethod.setParameter("mobileCode", mobileCode);
postMethod.setParameter("userID", userID);
//4.执行请求 ,结果码
int code=client.executeMethod(postMethod);
//5. 获取结果
String result=postMethod.getResponseBodyAsString();
System.out.println("Post请求的结果:"+result);
}
//2.Post请求 :通过Http-Client 框架来模拟实现 Http请求
public void soap() throws Exception{
HttpClient client=new HttpClient();
PostMethod postMethod=new PostMethod("http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx");
//3.设置请求参数
postMethod.setRequestBody(new FileInputStream("c:/soap.xml"));
//修改请求的头部
postMethod.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
//4.执行请求 ,结果码
int code=client.executeMethod(postMethod);
System.out.println("结果码:"+code);
//5. 获取结果
String result=postMethod.getResponseBodyAsString();
System.out.println("Post请求的结果:"+result);
}
public static void main(String[] args) throws Exception{
MobileCodeService ws=new MobileCodeService();
ws.get("15626217879", "");
ws.post("15626217879", "");
// ws.soap();
}
}
```
使用Wsimpot命令生成webservice的本地代理,通过本地代理访问webservice
命令语句:来解析WSDL文件其实就是xml文件
wsimport [opations]
- wsdl_uri:wsdl 的统一资源标识符
- d :指定要输出的文件的位置
- s :表示要解析java的源码 ,默认解析出的是class字节码
- p : 指定输出的包名
wsimport –s ./ -p cn.it.ws.c http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?WSDL
./:代表存放当前路径
执行语句会生成java源码和class字节码文件
使用java代码中的代理就可以调用web service中的工能。不能自己改变java代码,相当于不能改变代理
### 使用CXF框架,发布webservice服务,并使用客户端远程访问webservice
1. CXF介绍 :soa的框架
* cxf 是 Celtrix (ESB框架)和 XFire(webserivice) 合并而成,并且捐给了apache
* CxF的核心是org.apache.cxf.Bus(总线),类似于Spring的 ApplicationContext
* CXF默认是依赖于Spring的
* Apache CXF 发行包中的jar,如果全部放到lib中,需要 JDK1.6 及以上,否则会报JAX-WS版本不一致的问题
* CXF 内置了Jetty服务器 ,它是servlet容器,好比tomcat
CXF框架概念介绍
Apache CXF 是一个开源的 Services 框架,CXF 帮助您来构建和开发 Services 这些 Services 可以支持多种协议,比如:SOAP、POST/HTTP、RESTful HTTP CXF 大大简化了 Service可以天然地和 Spring 进行无缝集成。
2.CXF特点
1. 与Spring、Servlet做了无缝对接,cxf框架里面集成了Servlet容器Jetty
2. 支持注解的方式来发布webservice
3. 能够显示一个webservice的服务列表
4. 能够添加拦截器:输入拦截器、输出拦截器 :
输入日志信息拦截器、输出日志拦截器、用户权限认证的拦截器
### Spring+CXF整合来管理webservice
实现步骤:
1. 添加cxf.jar 包(集成了Spring.jar、servlet.jar ),spring.jar包 ,servlet.jar 包
2. 编写业务类,通过CXF来发布webservice
员工管理:
方法 :添加员工、查询员工
3. 添加一个CXF请求的 Servlet,用来处理webservice的请求
过滤的地址/ws/*
4. 配置Spring的配置文件: applicationContext.xml ,把cxf的bean在spring配置
5. 在web.xml中配置 CXF的 Servlet , 添加spring的监听
6. 通过wsimport生成本地代理 ,访问webservice
### weblogic
集群步骤
1.创建多个服务器
AdminServer(默认)
监听地址:127.0.0.1
服务器端口:7001
server-1:
监听地址127.0.0.1(不要写localhost)
服务器端口号7002
server-2:
监听地址127.0.0.1
服务器端口号7003
2.部署到项目到这两个服务器
web项目在tomcat发不完之后,才会在部署-》安装(找到web项目所在的路径)下面才会显示web项目
然后部署到这两个服务器上面。
3.使用D:\Oracle\Middleware\user_projects\domains\base_domain\bin下的startManagedWeblogic.cmd(启动受管服务器得命令server-1,server-2)
C:\Users\Administrator>D:\Oracle\Middleware\user_projects\domains\base_domain\bin\startManagedWebLogic.cmd Server-1 http://127.0.0.1:7001(Server-1名称大写敏感)
被管理服务器名 管理服务器的ip
验证:部署,部署到两个服务器的项目,测试,看一下是否成功
4.新建一个代理服务器
监听地址:127.0.0.1
端口:7000
5.1创建集群
名:Cluster-0
多点传送
239.192.0.0
端口:7777
5.2添加server到集群(server必须关闭状态[cdm命令行trl+c关闭])
放入两个server,不要放proxy
6.使用quick start进行扩展域
get start…找到已创建的base-domain域,下一步,选择第二个jax-rpc(weblogic的访问模式)勾选受管服务器,集群和部署服务两项配置受管得服务器,下一步到向集群分发服务器(可以看默认有两个server在里面)创建http代理勾选http代理,指定用proxy代理两个server下一步到将要部署定位到集群或服务器,在cluster-0下选择那个已经部署到两个server的项目(testweblogic4t),下一步到扩展,结束。
总结:扩展域过程中,除了配置勾选http指定定代理server,其余过程都可以默认不用勾选。
会在D:\Oracle\Middleware\user_projects\domains\base_domain\apps\生成(OracleProxy4_Cluster-0_Proxy)
OracleProxy4_Cluster-0_Proxy这个文件夹中封装了集群信息。(文件夹放到项目所在目录)
修改这个文件夹中的weblogic.xml为:(访问路径)
/testweblogic4t
7.回到console,进行安装部署OracleProxy4_Cluster-0_Proxy
服务器选择Proxy这个代理服务器,下一步,到完成
8.删除已经部署过的testweblogic4t项目重新部署到所有的集群,而不是再单个部署到每一个server中。
9.启动server-1,server-2.Proxy服务
C:\Users\Administrator>D:\Oracle\Middleware\user_projects\domains\base_domain\bin\startManagedWebLogic.cmd Server-1 http://127.0.0.1:7001
C:\Users\Administrator>D:\Oracle\Middleware\user_projects\domains\base_domain\bin\startManagedWebLogic.cmd Server-2 http://127.0.0.1:7001
C:\Users\Administrator>D:\Oracle\Middleware\user_projects\domains\base_domain\bin\startManagedWebLogic.cmd Proxy http://127.0.0.1:7001
10.在console集群中的项目进行测试。
通过console部署指定的文件夹下的项目:
这个项目必须是war包或者从tomcat安装目录下的webapps中已经部署到tomcat中的项目。
例如console要部署weblogictest文件夹下面的项目testweblogic4t,那么这个testweblogic4t一定是tomcat部署过的。要么是war包,要么是从webapps目录下拷贝过来的。这时console中指定安装目录下才会显示这个项目testweblogic4t,可以进行部署。
项目中属性project facets java版本和web module版本与开发工具环境有关。
开发工具环境越高版本项目中属性project facets java版本和web module版本就越高
部署正确到weblogic oracleweblogic server 11gr1(10.3.6)服务器的条件:
项目中project facets的java版本小于等于1.6,web module小于等于2.5,跟有无jdk环境和服务器环境包无关。
index.jsp保存原因是没有导入服务器包weblogic system library或者tomcat system library。
项目是否报错原因:
1.开发工具指定jdk环境版本小于项目中属性project facets的java版本。
出现的原因:例如:原来开发工具环境1.8jdk,项目中属性project facets的java版本1.8, 这是降低开发工具环境版本就会报错。
不管eclipse的开发环境jdk版本是多少,与项目中实际引入的jdk版本是无关的,不会 报错,项目中有无jdk版本和服务器环境(如:tomcat system library)无关,不会报错。
2.代码错误。
当有项目报错时,tomcat无法部署任何项目。而weblogic是可以的。
eclipse中部署到tomcat6服务器的条件:除添加不是tomcat环境包(如:weblogic system library)情况下都可以部署。
集群的负载均衡:(使用不同浏览器测试)
一个session访问一个资源时,代理服务器,使用server-1
另一个session访问同一个资源时,代理服务器,会使用server-2.
集群的故障转移:
如:
server-2进行登录成功,jsp页面显示两个sessionid同时对应一个会话。后server-2停掉
仍然进行其他操作时,代理proxy就会启动server-1进行继续业务操作。这是jsp页面就只剩一个活跃状态的sessionid。
### linux
#### Linux目录结构

1.bin : 存放的可执行的二进制文件
cd ls su passwd
2. boot :存放系统的引导文件的目录
3. dev 存放设备文件的目录,linux把设置当做文件来处理
4. etc : 存放系统的配置文件的目录
5. home :存放所有用户文件的根目录
,root用户除外
6. lib :共享库
7.usr :好比program files
存放应用的安装的路径
8 opt : 自定义存放应用程序位置
9. mnt :临时文件系统的挂靠点
ls –l[查看本目录下所有目录的信息权限]
#### 目录结构及权限
- 文件权限分析
w :可写 r: 只读 x:可执行 - :无权限
文件权限
1. 字符表示法
drwxr-xr-x(目录权限)
第一个字符表示文件的类型
d :普通文件
- :文件夹
c :串口文件
l :连接文件
2-4(rwx) 字符 : 该文件的属主用户的权限(读写执行)
5-7(r-x)字符 : 与属主用户同一组的其他用户的权限(‘-‘无权限)
8-10(r-x)字符 : 不同组的其他用户的权限(‘-‘无权限)
2. 数字表示法
-rw-r--r-- :表示这个文件的默认权限 644
二进制:
1111 1111 1111 1111 1111 1111 1111 1111(32位)
八进制:
111 111 111 111 111 111 111 111(一位最大值为7)
rw-代表1106
r—代表1004
drwxr-xr-x :表示目录的默认权限 755
默认有6个命令交互通道和一个图形界面交互通道,默认进入到的是图形界面通道
命令交互模式切换:ctrl+alt+f1---f6
图形交互界面 ctrl+alt+f7
1.图形界面交互模式
- terminal: 图形界面的命令终端,它是图形界面交互通道的延伸,要依赖于图形界面
2.命令交互模式
命令提示符:
itcast@ubuntu:~$
- itcast:用户名
- ubuntu :主机名
- ~ :路径 ,假如当前的路径正好是 该用户存放数据的根目录 ,则显示~
- $ :用户的类型 $代表普通用户 # 代表 超级用户
进入桌面的命令
volc@ubuntu:~/Desktop/a/b$ cd ~/Desktop
cd ..[表示返回上一目录]
cd a[表示进入当前目录下的a文件夹]
volc@ubuntu:~$ cd Desktop[表示在volc当前目录下进入 Desktop桌面]
1.注销、关机、重启
- 注销 :logout :登出 、exit
- 关机 :
shutdown - h 时间
- h :关机
- 时间 :
1. now :马上
2. 12.30 :指定具体时间
3. 3 :几分钟以后
sudo : superuser do :由超级用户来执行该命令
要配置sudo 命令 : 授权 哪些用户能执行哪些命令
由超级用户配置 sudo
/etc/sudoers
sudo shutdown -h now 当前账号:itcast
- 重启 :
shutdown -r 时间
-r :restart
2.linux基本命令 :文件操作命令
1. ls : 查看目录内容
- l :查看详细信息
- a :查看所有文件(隐藏)
man :manual : 手工,帮助 ,帮助命令,好比windows help
命令: man ls
2. mkdir :创建目录
Desktop:
- java
- JEE : aa.txt bb.txt
- Android
3. cd 切换目录
- cd .. 记得要加空格
- cd ./java 进入当前目录的子目录
- cd ../xxx 进入上一级目录的子目录
tab :自动补全
4. touch :创建一个空白的普通文件
touch aa.txt
5. echo :把内容重定向到指定的文件中 ,有则打开,无则创建
6. cat、more :查看文件内容
- cat :查看文件内容
- more :分页查看文件内容,按空格键换页
7. cp、mv、rm
- cp :复制
cp bj.txt ./java/jee
- mv :剪切、重命名
1. 剪切 :mv aa.txt ../android/
2. 重命名 :假如剪切的文件 存放在同一个目录中 ,则是重命名
mv bb.txt cc.txt
- rm :删除文件或者文件夹
-f : 假如要删除的文件不存在,也不提示
-i : 删除前提示 ,默认不删除,要删除,输入y
-d : 删除空白目录
-r :递归删除
8. wc :word count :统计字符数
154 233 3418
- 154 :行数
- 233 :单词数
- 3418 :字符数
命令: wc bj.txt
9. ln :创建连接文件
- 默认创建的是硬连接,好比复制 ,但是两个文件会同步
命令:ln ./java/android/aa.txt aaa
- s :创建的是软连接
10. pwd :查看当前目录的绝对路径
11. 管道命令 |
命令: ls -la | wc
12. 重定向
- > :覆盖模式
命令: echo "ww">aaa
- >>:追加模式
命令: echo "ww">>aaa
13. passwd :设置密码 ,ubuntu默认 root账号是没有开启 ,只要设置root密码即可开启
sudo passwd root
14. su 切换目录
su root
root用户切换到其他账号不需要密码
3.linux 系统命令
1.stat :查看文件的详细信息
stat bj.txt
2.who与whoami
who : 查看在线的用户
whoami :查看当前自己的用户
3.hostname : 显示主机名
hostname
4.uname :显示系统信息
-a :显示完整的系统信息
5.top :显示当前耗时的进行的信息 ,每3秒刷新一次
cltr+c 中断
6.ps :显示当前进程的快照
- axu
7.du :显示文件的大小信息
8.df :磁盘使用情况 disk free
9.ifconfig :查看或者配置网卡信息 ,好比windows 的ipconfig
ipv4:32位 2-32次方 ipv6 128位 是 ipv4 2-96次方倍数
设置虚拟机ip地址:
1. 设置vmware的连接方式
- 共享宿主机的ip地址,在网上邻居找不到
- 桥接方式,需要单独设置ip,可以在网上邻居查找
2. 图形界面设置ip地址
edit connection --》ipv4--》manual(手工设置)--》add (ip地址,子网掩码)
3.命令方式设置ip地址
静态设置ip:
sudo ifconfig eth0 192.168.15.122 netmask 255.255.255.0
10.ping 测试与目标主机连接情况
11.clear : 清除屏幕 windows: cls
12.man :帮助命令
man 命令
13.kill :杀死进程
kill pid
14.netstat :网络连接详细信息
15. useradd
- 查看用户信息
sudo cat /etc/passwd
itcast:x:1000:1000:UbuntuA,,,:/home/itcast:/bin/bash
- itcast:用户名
- x :密码 :已经加密 ,密码存放在 /etc/shadow
- 1000: 账号id ,userId
- 1000: 组id ,group id
- UbuntuA,,, :账号描述
- /home/itcast :该账号存放文件的默认位置 ~
- /bin/bash:该用户的shell脚本的解析方式 ,sh 、bash、rbash
- 创建用户
sudo useradd lijun -d /home/lijun -s /bin/bash
-d :指定该用户的home 路径
- s :该用户的shell解析方式
步骤:
1. 创建 /home/lijun 目录
2. 执行 useradd 命令
3. 用 passwd 设置密码
4. su 切换用户
### Tomcat、Weblogic的区别
什么是weblogic
WebLogic是美国Oracle公司出品的一个application server确切的说是一个基于JAVAEE架构的中间件,BEA WebLogic是用于开发、集成、部署和管理大型分布式Web应用、网络应用和数据库应用的Java应用服务器。
| Weblogic特点 | Tomcat特点 |
| WLS全面支持J2EE的标准规范和其他标准规范,Web Service, SSL, xml,EJB等 | Tomcat 为WEB容器,只支持部分J2EE标准, 应用局限性强,不支持EJB |
| 完善的售后支持 | 没有售后支持, 看社区与论坛服务器出现的问题 |
| 集群机制, 支持分布式的应用 | 需要结合第三方插件/应用 |
| Web控制台进行组件、JDBC、管理和配置 | 差 |
| 较好的支持热部署(开发模式下)实现某个单一类的热部署,让系统无需重启就完成某个类的更新 | 差 |
| 需要费用 | 开源免费 |
### Lucene
Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包,Lucene是根据关健字来搜索的文本搜索工具,只能在某个网站内部搜索文本内容,不能跨网站搜索,Lucece不能用在互联网搜索(即像百度那样),只能用在网站内部的文本搜索。
lucene索引库的结构
词汇表:以单个汉字进行分词建立的索引库
“是”词汇的值有三个引用012分别作为三个数组,每个数组的值分别指向三个document对象
原始记录表:封装了document对象,document对象存放具体Article实例对象的属性值

Lucene程序宏观结构:

词汇表单个词汇的含义

创建索引库:
1) 创建JavaBean对象
2) 创建Docment对象
3) 将JavaBean对象所有的属性值,均放到Document对象中去,属性名可以和JavaBean相同或不同
4) 创建IndexWriter对象
5) 将Document对象通过IndexWriter对象写入索引库中
6) 关闭IndexWriter对象
根据关键字查询索引库中的内容:
1) 创建IndexSearcher对象
2) 创建QueryParser对象
3) 创建Query对象来封装关键字
4) 用IndexSearcher对象去索引库中查询符合条件的前100条记录,不足100条记录的以实际为准
5) 获取符合条件的编号
6) 用indexSearcher对象去索引库中查询编号对应的Document对象
7) 将Document对象中的所有属性取出,再封装回JavaBean对象中去,并加入到集合中保存,以备将之用
导包lucene
lucene-core-3.0.2.jar【Lucene核心】
lucene-analyzers-3.0.2.jar【分词器】
lucene-highlighter-3.0.2.jar【Lucene会将搜索出来的字,高亮显示,提示用户】
lucene-memory-3.0.2.jar【索引库优化策略】
代码示例:
```java
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Index;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.junit.Test;
import cn.volc.entity.Article;
public class FirstLucene {
/*
* 创建lucene索引库,包括,词汇表和原始数据(Article类型)
* 分为4个步骤
* 1.创建原始记录的数据。
* 2.创建索引库是通过document对象创建的,先创建一个document,用来封装原始记录数据。
* 3.将document对象写入到lucene索引库中。那么Lucene索引库中包含,词汇表和document对象(document对象封装了原始数据article对象)。
* 4.关闭索引字符流对象。
*/
@Test
public void createIndexDB() throws Exception{
//1.创建原始记录的数据。
Article article = new Article(1,"原始数据头标题title","原始数据的内容content");
//2.创建索引库是通过document对象创建的,先创建一个document,用来封装原始记录数据,
Document document = new Document();
//2.2将article对象绑定到document中。document存放的字段field,field用来封装原始记录的信息
//每一个field包括三个参数
/*
* 参数一:document的属性名"id",项目中提倡与article属性名称相同
* 参数二:document对象中属性"id"的值为article的属性id,与article对象中相同
* 参数三:是否将id属性值存入到有原始记录转存入到词汇表
* 项目中非id值都提倡放入词汇表中
* 参数四:是否将id属性值进行分词算法拆分
* 项目中非id属性都提倡进行拆分
*/
document.add(new Field("id",article.getId().toString(),Store.YES,Index.ANALYZED));
document.add(new Field("title",article.getTitle(),Store.YES,Index.ANALYZED));
document.add(new Field("content",article.getContent(),Store.YES,Index.ANALYZED));
//3.将document对象写入到lucene索引库中,那么Lucene索引库中包含,词汇表和document对象(document对象封装了原始数据article对象)
Directory directory = FSDirectory.open(new File("E:/eworkspace/lucene-01/LuceneDBDBDBDBDBDBDBDBDB"));
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
MaxFieldLength maxFieldLength = MaxFieldLength.LIMITED;
/*
* 参数一:lucene索引库最终对应硬盘中的目录,"E:/eworkspace/lucene-01/LuceneDBDBDBDBDBDBDBDBDB",如果没有将自动创建
* 参数二:采用什么策略将文本拆分,查看策略就是它的实现类(ctrl+T选中IndexWriter查看它的实现类)
* 参数三:最多将文本拆分成多少个词汇,LIMITED表示1w个,也就是field的值取前1万个(拆分策略是一个汉字作为一个词汇)作为词汇。
* 不足1万个以实际为准,例如值有5个汉字,就把这5个汉字作为词汇
*/
//3.1创建一个索引对象,(指定索引存放硬盘的目录,文本拆分策略,最多拆分词汇数目)
IndexWriter indexWriter = new IndexWriter(directory,analyzer,maxFieldLength);
//3.2真正将document对象写入到lucene索引库中
indexWriter.addDocument(document);
//4.关闭索引字符流对象
indexWriter.close();
}
/*
* 根据关键字从索引库中查询符合条件的content
*/
@Test
public void findIndexDB() throws Exception{
//1.创建集合用于接收数据对象
List articleList = new ArrayList();
//指定关键字
String keywords = "内"; //这样两个汉字搜索是可以的,lucene索引关键字不能为空,为空会报错,含有空格也不行
Directory directory = FSDirectory.open(new File("E:/eworkspace/lucene-01/LuceneDBDBDBDBDBDBDBDBDB"));
Version version = Version.LUCENE_30;
//解析器类型(版本号)
Analyzer analyzer = new StandardAnalyzer(version);
//创建查询解析器或查询策略对象(指定策略版本,搜索document的哪个字段,解析策略)
/*
* 参数一:分词器版本,提倡使用该jar包中的最高版本
* 参数二:针对document哪个字段进行搜索(根据"content"搜索)
* 参数三:指定标准解析策略
*/
QueryParser queryParser = new QueryParser(version,"content",analyzer);
//通过查询解析器解析一个查询对象(查询对象带有关键字)用于查询。
Query query = queryParser.parse(keywords);
//2.创建搜索字符流对象IndexSearcher,指定搜索索引库在硬盘的具体目录
IndexSearcher indexSearcher = new IndexSearcher(directory);
int MAN_RECORD = 10;
//3.通过搜索字符流对象indexSearcher进行搜索(根据关键字,去索引库中的词汇表中进行搜索的)
/*
* 参数一:表示封装关键字的查询对象
* 参数二:如果关键字搜索出来的内容较多只取前MAN_RECORD个内容
* 不足MAN_RECORD以实际为准
*/
//3.通过搜索字符流对象进行搜索(指定查询对象 ,查询记录数),返回词汇表记录
TopDocs topDocs = indexSearcher.search(query, MAN_RECORD);
//4.获取词汇表的数组,然后遍历词汇表中符合条件的编号,scoreDocs代表三个[0],[1],[2]数组集合,也就是符合条件的document的个数
for(int i=0;i findAllObjectWithFY(String keywords,Integer start,Integer size) throws Exception{
List articleList = new ArrayList();
QueryParser queryParser = new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer());
Query query = queryParser.parse(keywords);
IndexSearcher indexSearcher = new IndexSearcher(LuceneUtil.getDirectory());
TopDocs topDocs = indexSearcher.search(query,100000000);
/*
* 判断是否为最后几条,如果最后几条个数小于了一页显示的个数,即topDocs.totalHits articleList = new ArrayList();
public PageBean(){}
public Integer getAllObjectNum() {
return allObjectNum;
}
public void setAllObjectNum(Integer allObjectNum) {
this.allObjectNum = allObjectNum;
if(this.allObjectNum % this.perPageNum == 0){
this.allPageNum = this.allObjectNum / this.perPageNum;
}else{
this.allPageNum = this.allObjectNum / this.perPageNum + 1;
}
}
public Integer getAllPageNum() {
return allPageNum;
}
public void setAllPageNum(Integer allPageNum) {
this.allPageNum = allPageNum;
}
public Integer getCurrPageNum() {
return currPageNum;
}
public void setCurrPageNum(Integer currPageNum) {
this.currPageNum = currPageNum;
}
public Integer getPerPageNum() {
return perPageNum;
}
public void setPerPageNum(Integer perPageNum) {
this.perPageNum = perPageNum;
}
public List getArticleList() {
return articleList;
}
public void setArticleList(List articleList) {
this.articleList = articleList;
}
}
```
步三:创建ArticleService.java类
```java
public class ArticleService {
private ArticleDao articleDao = new ArticleDao();
public PageBean fy(String keywords,Integer currPageNum) throws Exception{
PageBean pageBean = new PageBean();
pageBean.setCurrPageNum(currPageNum);
Integer allObjectNum = articleDao.getAllObjectNum(keywords);
pageBean.setAllObjectNum(allObjectNum);
Integer size = pageBean.getPerPageNum();
Integer start = (pageBean.getCurrPageNum()-1) * size;
List articleList = articleDao.findAllObjectWithFY(keywords,start,size);
pageBean.setArticleList(articleList);
return pageBean;
}
}
```
步四:创建ArticleServlet.java类
```java
public class ArticleServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
try {
request.setCharacterEncoding("UTF-8");
Integer currPageNum = Integer.parseInt(request.getParameter("currPageNum"));
String keywords = request.getParameter("keywords");
ArticleService articleService = new ArticleService();
PageBean pageBean = articleService.fy(keywords,currPageNum);
request.setAttribute("pageBean",pageBean);
request.getRequestDispatcher("/list.jsp").forward(request,response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
```
第五步:导入EasyUI相关的js包的目录

步六:在WebRoot目录下创建list.jsp
```
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
```
步六:在WebRoot目录下创建list2.jsp
```
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
根据关键字分页查询所有信息
```
### activiti
Activiti5是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理、工作流、服务协作等领域的一个开源的、灵活的、易扩展的可执行流程语言框架。Activiti基于Apache许可的开源BPM平台,创始人Tom Baeyens是JBoss jBPM的项目架构师,它特色是提供了eclipse插件,开发人员可以通过插件直接绘画出业务
流程图。
工作流概念
oa系统、电子政务 经常采用工作流
activiti工作流包括
1. 工作流引擎 :ProcessEngine ,它是Activiti的核心类,由该类可以获取其他的服务实例
(历史服务、仓库服务、任务服务、用户参与者服务)
2. BPMN :UML :用例图、类图、时序图
业务流程建模与标注(Business Process Model and Notation,BPMN) ,
描述流程的基本符号,包括这些图元如何组合成一个业务流程图(Business Process Diagram)
3. 数据库
Activiti的后台是有数据库的支持,所有的表都以ACT_开头。
第二部分是表示表的用途的两个字母标识。 用途也和服务的API对应
Activiti的工作流数据库有23张表
要保存流程定义
- act_ge_* :通用表
- act_hi_* :历史流程相关表
- act_re_* :仓库表:保存流程定义
- act_ru_* :保存流程运行相关的表
- act_id_* :用户参与相关的表
4. activiti.cfg.xml
Activiti核心配置文件,配置流程引擎创建工具的基本参数和数据库连接参数
5. logging.properties :log4j

模拟activiti执行流程框架
1.创建activiti project工程,不关联项目,添加所有的activiti框架的jar包
1.2.配置ProcessEngineConfiguration工作流引擎。activiti.cfg.xml配置文件和log4j.properties
2.设置流程定义图bpmn(业务流程建模标注)
```
```
右击diagram目录新建一个activiti diagram流程图,创建流程图,编写每一个流程的信息
General和main config配置信息


指定当前流程有哪个人来审批,指定人名

流程引擎类结构:

3.通过代码的形式在ActivitiTest.java类中创建流程引擎对象。代替activiti.cfg.xml中的配置(选其一)
```java
import java.util.List;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.junit.Test;
/**
* 模拟activiti工作流的框架
* @author Administrator
*/
public class ActivitiTest {
private ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
@Test
//创建activiti涉及的数据库和表
public void createProcessEnginer(){
/**
* 1.通过代码形式创建
* 1.1获取ProcessEngineConfiguration对象
* 1.2设置数据路连接属性
* 1.3当没有表时设置创建表的策略
* 1.4通过ProcessEngineConfiguration创建ProcessEnginer对象
*/
/*
//1.1获取ProcessEngineConfiguration对象
ProcessEngineConfiguration configuration = ProcessEngineConfiguration.
createStandaloneProcessEngineConfiguration();
configuration.setJdbcDriver("com.mysql.jdbc.Driver");
//1.2设置数据路连接属性
//带参数url不存在则创建,设置字符集编码格式(自动创建activitidb数据库和23张表) configuration.setJdbcUrl("jdbc:mysql://localhost:3306/activitiDB?createDatabaseIfNotExist=true"+
"&useUnicode=true&characterEncoding=utf8");
configuration.setJdbcUsername("root");
configuration.setJdbcPassword("root");
//1.3当没有表时设置创建表的策略
// public static final java.lang.String DB_SCHEMA_UPDATE_FALSE = "false";
// public static final java.lang.String DB_SCHEMA_UPDATE_CREATE_DROP = "create-drop";
// public static final java.lang.String DB_SCHEMA_UPDATE_TRUE = "true";//假如没有表会自动创建表
configuration.setDatabaseSchemaUpdate("true");
//1.4通过ProcessEngineConfiguration创建ProcessEnginer对象
ProcessEngine buildProcessEngine = configuration.buildProcessEngine();
System.out.println("流程引擎创建成功" + buildProcessEngine);
*/
/*
* 2.通过加载activit.cfg.xml获取流程引擎和自动创建数据库及表
从类的加载路径中加载资源activiti.cfg.xml配置文件
*/
/*ProcessEngineConfiguration configuration = ProcessEngineConfiguration.
createProcessEngineConfigurationFromResource("activiti.cfg.xml");//从类的加载路径
ProcessEngine buildProcessEngine = configuration.buildProcessEngine();
System.out.println("通过activiti.cfg.xml文件创建流程引擎对象" + buildProcessEngine);*/
/*
* 3.通过默认加载类路径下activiti.cfg.xml
*/
System.out.println("通过加载默认的类路径下的配置文件方法获取流引擎对象" + defaultProcessEngine);
}
}
```
4. 部署流程定义
```java
/*
* 部署流程定义
*/
@Test
public void deploy(){
//获取流程引擎对象
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.addClasspathResource("diagrams/LeaveBill.bpmn")
.addClasspathResource("diagrams/LeaveBill.png")
.name("请假单流程图")//设置部署的名称
.category("办公类别")//设置部署类别
.deploy();//真正部署
System.out.println("部署流程图的对象的id" + deploy.getId());
System.out.println("部署流程图的对象的名称" + deploy.getName());
}
```
5.执行流程
```java
//执行流程
@Test
public void startProcess(){
String processValue = "leavebill";
RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
//取得流程实例
ProcessInstance processInstanceByKey = runtimeService.startProcessInstanceByKey(processValue);
System.out.println("流程实例的id" + processInstanceByKey.getId());
System.out.println("流程定义的id" + processInstanceByKey.getProcessDefinitionId());
}
```
6. 查询任务
```java
//查询任务
@Test
public void queryTask(){
String name = "张三";
TaskService taskService = defaultProcessEngine.getTaskService();
//创建一个任务查询对象
TaskQuery createTaskQuery = taskService.createTaskQuery();
//查询办理人的任务列表
List list = createTaskQuery.taskAssignee(name)
.list();
//查询到任务列表,遍历
if(list != null && list.size() > 0){
for(Task task : list){
System.out.println("任务办理人" + task.getAssignee());
System.out.println("任务id" + task.getId());
System.out.println("任务名称" + task.getName());
}
}
}
```
7.完成任务
```java
//完成任务
@Test
public void compileTask(){
String taskId = "104";
TaskService taskService = defaultProcessEngine.getTaskService();
taskService.complete(taskId);
System.out.println("执行任务完成");
}
```
### Maven
Maven是一个采用纯Java编写的开源项目管理工具, Maven采用了一种被称之为Project Object Model (POM)概念来管理项目,所有的项目配置信息都被定义在一个叫做POM.xml的文件中, 通过该文件Maven可以管理项目的整个生命周期,包括清除、编译,测试,报告、打包、部署等等
Maven能够做什么
Jar的声明式依赖性管理
项目自动构建
使用需求
- 企业岗位需求
- 软件开发中遇到的问题
1. jar包的依赖与管理
项目中有很多jar包:
问题:不能确定jar包的完全正确性、不同技术框架版本的管理、jar包的依赖
2. 自动构建项目
- 软件开发: 可行性分析、需求分析、软件设计、软件开发、发布、运维
- 软件构建: 软件已经开发完毕,需要构建成一个产品进行发布
构建步骤:
清除--> 编译-->测试-->报告-->打包(jar\war)-->安装-->部署到远程
maven可以通过一个命令实现自动构建软件项目
pom.xml
```xml
4.0.0
cn.itcast.maven
Hello
0.0.1-SNAPSHOT
junit
junit
4.9
test
```
使用Maven用例
1. 1.4.1. HelloFriend目录结构
HelloFriend
--src
-----main
----------java
----------resources
-----test
---------java
---------resources
--pom.xml
建立pom.xml
```xml
4.0.0
cn.itcast.maven
HelloFriend
1.0.0
jar
junit
junit
4.9
test
cn.itcast.maven
Hello
1.0.0
compile
```
在src/main/java/cn/itcast/maven目录下新建文件HelloFriend.java
```java
public class HelloFriend{
public String sayHello(String name){
return "Hello "+name+"!";
}
}
```
在/src/test/java/cn/itcast/maven目录下新建测试文件HelloFriendTest.java
```java
import org.junit.Test;
import cn.itcast.maven.Hello;
public class HelloFriendTest {
@Test
public void tesHelloFriend(){
HelloFriend helloFriend = new HelloFriend();
String results = helloFriend.sayHelloToFriend("litingwei");
System.out.println(results);
}
}
```
命令测试
```
在HelloFriend目录下执行 mvn clean mvn compile mvn test 都正常
在HelloFriend目录下执行命令mvn package 系统报错说没有找到依赖, 因为HelloFriend依赖Hello模块,但是此模块在个人仓库和中央仓库中并不存在
需要重新构建Hello第一个项目并安装到数据仓库, 在Hello根目录下执行mvn clean install, 就会部署的中央仓库中
```
生命周期

### Quartz(制定任务详细执行时间)
QuartzTask.java
```java
import java.text.SimpleDateFormat;
import java.util.Date;
public class QuartzTask {
public void doSimpleTriggerTask() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("doing simpleTrigger task..." + sdf.format(new Date()));
}
public void doCronTriggerTask() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("doing cronTrigger task..." + sdf.format(new Date()));
}
}
```
complain-spring.xml配置//在每月的月底下午的3点每分钟的第10秒执行,自动处理过期投诉数据
```xml
```
quartz-spring.xml
```xml
```
### 2345公司面试题
#### ++、--是否是线程安全的,为什么
i++和++i的线程安全分为两种情况:
1、如果i是局部变量(在方法里定义的),那么是线程安全的。因为局部变量是线程私有的,别的线程访问不到,其实也可以说没有线程安不安全之说,因为别的线程对他造不成影响。
2、如果i是全局变量(类的成员变量),那么是线程不安全的。因为如果是全局变量的话,同一进程中的不同线程都有可能访问到。
如果有大量线程同时执行i++操作,i变量的副本拷贝到每个线程的线程栈,当同时有两个线程栈以上的线程读取线程变量,假如此时是1的话,那么同时执行i++操作,再写入到全局变量,最后两个线程执行完,i会等于3而不会是2,所以,出现不安全性。
解决方法:
1、对 i++ 操作的方法加同步锁,同时只能有一个线程执行 i++ 操作
2、使用支持原子性操作的类,如 java.util.concurrent.atomic.AtomicInteger,它使用的是 CAS 算法,效率优于第 1 种
#### Spring IOC的理解和原理
参阅: https://www.cnblogs.com/xdp-gacl/p/4249939.html
##### 理解
Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
●谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)
●为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
##### IOC(控制反转)原理
Spring容器高层视图

Bean缓存池:HashMap实现
Spring 通过一个配置文件描述 Bean 及 Bean 之间的依赖关系,利用 Java 语言的反射功能实例化 Bean 并建立 Bean 之间的依赖关系
1. BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身,使用的是工厂设计模式
2. ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合我们都直接使用 ApplicationContext 而非底层的 BeanFactory。
###### BeanFactory
BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;
###### ApplicationContext
ApplicationContext 由 BeanFactory 派生而来,提供了更多面向实际应用的功能。
在BeanFactory 中,很多功能需要以编程的方式实现,而在 ApplicationContext 中则可以通过配置的方式实现。
##### DI(Dependency Injection,依赖注入)原理
IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,
依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了
spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。
在系统运行时,spring会在适当的时候制造一个Connection
总结:
1. SpringIOC容器主要有继承体系底层的BeanFactory、高层的ApplicationContext和WebApplicationContext
2. Bean有自己的生命周期
3. 容器启动原理:Spring应用的IOC容器通过tomcat的Servlet或Listener监听启动加载;Spring MVC的容器由DispatchServlet作为入口加载;Spring容器是Spring MVC容器的父容器
4. 容器加载Bean原理:
BeanDefinitionReader读取Resource所指向的配置文件资源,然后解析配置文件。配置文件中每一个解析成一个BeanDefinition对象,并保存到BeanDefinitionRegistry中;
容器扫描BeanDefinitionRegistry中的BeanDefinition;调用InstantiationStrategy进行Bean实例化的工作;使用BeanWrapper完成Bean属性的设置工作;
单例Bean缓存池:Spring 在 DefaultSingletonBeanRegistry 类中提供了一个用于缓存单实例 Bean 的缓存器,它是一个用 HashMap 实现的缓存器,单实例的 Bean 以 beanName 为键保存在这个HashMap 中。
参考:https://zhuanlan.zhihu.com/p/29344811
#### AOP面向切面原理
AOP是OOP的延续,是(Aspect Oriented Programming)的缩写,意思是面向切面编程。要理解AOP首先得弄明白代理的概念。对于代理看下点击打开链接这篇文章。
AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理、日志等。 AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理则可分为静态代理和动态代理两大类,其中静态代理是指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;而动态代理则在运行时借助于 JDK 动态代理、CGLIB 等在内存中"临时"生成 AOP 动态代理类,因此也被称为运行时增强。
知道这些其他的就是些配置了。
#### 堆和栈的区别
1.栈内存存储的是局部变量,基础数据,而堆内存存储的是实体(new的对象);
2.栈内存的更新速度要快于堆内存,因为局部变量的生命周期很短;
3.栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收。Java的堆是一个运行时数据区,堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小。
4.如果栈内存没有可用的空间存储方法调用和局部变量,JVM会抛出java.lang.StackOverFlowError。
而如果是堆内存没有可用的空间存储生成的对象,JVM会抛出java.lang.OutOfMemoryError
5.栈中的数据共享的区别,和两个对象引用同时执行同一个堆中对象是不同的。通过一个对象的引用改变对象的数据,那么另一个对象的引用所指向的堆中的对象数据也会改变。而在栈中int a = 1;int b = 1; a改变不会影响b的值。
#### 对象的值相同(y.equals(x) == true),hash code相同吗,为什么
不一定相同。正常情况下,因为equals()方法比较的就是对象在内存中的值,如果值相同,那么Hashcode值也应该相同。但是如果不重写hashcode方法,就会出现不相等的情况。
通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
1.equals() 用于判断两个对象的数据、内容是否一致。
2.hashCode()用于生成一个哈希码(相应对象整型的 hash 值),便于HashMap使用,系统默认实现是计算对象的内存地址,转换成一个整数。 它们之间没什么联系,两个相等的对象生成的HASH码应该是相等的,但是HASH码相等并不能保证两个对象相等。关键在于你对相等的定义(也就是重写equals函数),与此同时,也应该重写hashCode函数保证上述关系。
== 是比较地址是否相等,JAVA中声明变量都是引用嘛,不同的引用,可能指向同一个地址。
equals 是比较值是否相等。
如果是基本变量,没有hashcode和equals方法,基本变量的比较方式就只有==;
如果是变量要比较实际内存中的内容,那就要用equals方法
#### 线程池的作用
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三:可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。
#### Java实现线程同步的方式
1.同步方法
即有synchronized关键字修饰的方法。 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。
注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类。
2. 同步代码块
即有synchronized关键字修饰的语句块。 被该关键字修饰的语句块会自动被加上内置锁,从而实现同步
代码如:
synchronized(object){
}
3. wait与notify
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
4. 使用特殊域变量(volatile)实现线程同步
```java
//只给出要修改的代码,其余代码与上同
class Bank {
//需要同步的变量加上volatile
private volatile int account = 100;
public int getAccount() {
return account;
}
//这里不再需要synchronized
public void save(int money) {
account += money;
}
}
```
5. 使用重入锁实现线程同步
6. 使用阻塞队列实现线程同步
前面几种同步方式都是在底层实现的线程同步,但是我们在实际开发当中,应当尽量远离底层结构。 使用javaSE5.0版本中新增的java.util.concurrent包将有助于简化开发。 本小节主要是使用LinkedBlockingQueue来实现线程的同步LinkedBlockingQueue是一个基于已连接节点的,范围任意的blocking queue。队列是先进先出的顺序(FIFO),关于队列以后会详细讲解~
LinkedBlockingQueue 类常用方法 LinkedBlockingQueue() : 创建一个容量为Integer.MAX_VALUE的LinkedBlockingQueue put(E e) :
在队尾添加一个元素,如果队列满则阻塞 size() : 返回队列中的元素个数 take() : 移除并返回队头元素,如果队列空则阻塞代码实例:
实现商家生产商品和买卖商品的同步
注:BlockingQueue定义了阻塞队列的常用方法,尤其是三种添加元素的方法,我们要多加注意,当队列满时:
add()方法会抛出异常
offer()方法返回false
put()方法会阻塞
#### 修饰符范围由大到小排序
(1)public:可以被所有其他类所访问。
(2)private:只能被自己访问和修改。
(3)protected:自身,子类及同一个包中类可以访问。
(4)default(默认):同一包中的类可以访问,声明时没有加修饰符,认为是friendly。
| 修饰符 | 类内部 | 本包 | 子类 | 外部包 |
| public | √ | √ | √ | √ |
| protected | √ | √ | √ | × |
| default | √ | √ | × | × |
| private | √ | × | × | × |
#### ArrayList和LinkedList的在存储方式上区别
ArrayList和Vector都是使用数组方式存储数据
LinkedList使用双向链表实现存储
#### 查看linux服务器的内存使用情况的命令
top命令可以实时动态地查看系统的整体运行情况,是一个综合了多方信息监测系统性能和运行信息的实用工具。通过top命令所提供的互动式界面,用热键可以管理。
```
[root@VM_0_11_redhat ~]# top
top - 18:23:21 up 83 days, 17:49, 2 users, load average: 0.00, 0.01, 0.05
Tasks: 75 total, 1 running, 74 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.7 us, 1.0 sy, 0.0 ni, 98.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1016516 total, 67664 free, 565684 used, 383168 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 278832 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
28924 root 20 0 740980 11396 1096 S 0.3 1.1 175:36.09 barad_agent
1 root 20 0 43188 2352 1204 S 0.0 0.2 6:09.23 systemd
```
查看RAM使用情况最简单的方法是通过/proc/meminfo
```
[root@VM_0_11_redhat ~]# cat /proc/meminfo
MemTotal: 1016516 kB
MemFree: 76552 kB
MemAvailable: 460296 kB
Buffers: 99964 kB
Cached: 368936 kB
SwapCached: 0 kB
Active: 585040 kB
Inactive: 232760 kB
Active(anon): 349044 kB
Inactive(anon): 144 kB
Active(file): 235996 kB
```
#### 添加优化查询速度索引的sql语句
需要添加普通类型的索引
普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。因此,应该只为那些最经常出现在查询条件(WHEREcolumn=)或排序条件(ORDERBYcolumn)中的数据列创建索引。只要有可能,就应该选择一个数据最整齐、最紧凑的数据列(如一个整数类型的数据列)来创建索引。
添加普通索引Sql:
INDEX(普通索引)
mysql>ALTER TABLE `table_name` ADD INDEX index_name ( `column` )
### mysql优化
#### sql优化
```sql
select * from a
left join b on b.id = a.id
left join c on c.id = b.id -- 慢的原因出在这
```
mysql查询存在直接关联和非直接关联的问题,这两种查询效率差别很大
#### List,set,map都同时继承了Conllection接口吗
不是
java.util.Collection [I]
+--java.util.List [I]
+--java.util.ArrayList [C]
+--java.util.LinkedList [C]
+--java.util.Vector [C]
+--java.util.Stack [C]
+--java.util.Set [I]
+--java.util.HashSet [C]
+--java.util.SortedSet [I]
+--java.util.TreeSet [C]
java.util.Map [I]
+--java.util.SortedMap [I]
+--java.util.TreeMap [C]
+--java.util.Hashtable [C]
+--java.util.HashMap [C]
+--java.util.LinkedHashMap [C]
+--java.util.WeakHashMap [C]
参考:http://android.blog.51cto.com/268543/400557
#### String a = new String(“abc”);创建了几个字符串对象
2个
#### 一个类的构造方法可以被其他对象调用吗
可以,但是不能像调用普通方法一样调用
在子类中的缺省构造器可以调用父类的缺省/非缺省构造器,在调用父类的缺省构造器时,
不用写super关键字直接可以调(因为super是隐式的);在调用父类的非缺省构造器时,
必须用super(参数)显示调用。如下面的案例所示:
同一类中,在构造方法中可以调用本类的其他构造
```java
public class Zi extends Fu {
public static String name = "123";
public Zi() { // 子类无惨构造不能直接调用父类有参构造,需要将name参数提前加载,static先加载再加载构造
super(name);
}
public static void main(String[] args) {
new Zi();
}
/**
* 1). 父类static(顺序按照代码书写顺序进行)
2). 子类static(顺序按照代码书写顺序进行)
3). 父类非static域、构造器(顺序按照代码书写顺序进行)
4). 子类非static域、构造器(顺序按照代码书写顺序进行)
*/
}
```
### 闭包
闭包是javascript一个非常重要的特性,意味着当前作用域总能够访问外部作用域的变量,因为函数是javascript唯一拥有自身作用域的结构,因此闭包的创建依赖于函数。
#### 什么是闭包
```html
就表示这个是临时表,后边的N就是执行计划中的id,表示结果来自于这个查询产生。如果是尖括号括起来的,与类似,也是一个临时表,表示这个结果来自于union查询的id为M,N的结果集。
4)、type
依次从好到差:system,const,eq_ref,ref,fulltext,ref_or_null,unique_subquery,index_subquery,range,index_merge,index,ALL,除了all之外,其他的type都可以使用到索引,除了index_merge之外,其他的type只可以用到一个索引
A:system:表中只有一行数据或者是空表,且只能用于myisam和memory表。如果是Innodb引擎表,type列在这个情况通常都是all或者index
B:const:使用唯一索引或者主键,返回记录一定是1行记录的等值where条件时,通常type是const。其他数据库也叫做唯一索引扫描
C:eq_ref:出现在要连接过个表的查询计划中,驱动表只返回一行数据,且这行数据是第二个表的主键或者唯一索引,且必须为not null,唯一索引和主键是多列时,只有所有的列都用作比较时才会出现eq_ref
D:ref:不像eq_ref那样要求连接顺序,也没有主键和唯一索引的要求,只要使用相等条件检索时就可能出现,常见与辅助索引的等值查找。或者多列主键、唯一索引中,使用第一个列之外的列作为等值查找也会出现,总之,返回数据不唯一的等值查找就可能出现。
E:fulltext:全文索引检索,要注意,全文索引的优先级很高,若全文索引和普通索引同时存在时,mysql不管代价,优先选择使用全文索引
F:ref_or_null:与ref方法类似,只是增加了null值的比较。实际用的不多。
G:unique_subquery:用于where中的in形式子查询,子查询返回不重复值唯一值
H:index_subquery:用于in形式子查询使用到了辅助索引或者in常数列表,子查询可能返回重复值,可以使用索引将子查询去重。
I:range:索引范围扫描,常见于使用>,<,is null,between ,in ,like等运算符的查询中。
J:index_merge:表示查询使用了两个以上的索引,最后取交集或者并集,常见and ,or的条件使用了不同的索引,官方排序这个在ref_or_null之后,但是实际上由于要读取所个索引,性能可能大部分时间都不如range
K:index:索引全表扫描,把索引从头到尾扫一遍,常见于使用索引列就可以处理不需要读取数据文件的查询、可以使用索引排序或者分组的查询。
L:all:这个就是全表扫描数据文件,然后再在server层进行过滤返回符合要求的记录。
5)、possible_keys
查询可能使用到的索引都会在这里列出来
6)、key
查询真正使用到的索引,select_type为index_merge时,这里可能出现两个以上的索引,其他的select_type这里只会出现一个。
7)、key_len
用于处理查询的索引长度,如果是单列索引,那就整个索引长度算进去,如果是多列索引,那么查询不一定都能使用到所有的列,具体使用到了多少个列的索引,这里就会计算进去,没有使用到的列,这里不会计算进去。留意下这个列的值,算一下你的多列索引总长度就知道有没有使用到所有的列了。要注意,mysql的ICP特性使用到的索引不会计入其中。另外,key_len只计算where条件用到的索引长度,而排序和分组就算用到了索引,也不会计算到key_len中。
8)、ref
如果是使用的常数等值查询,这里会显示const,如果是连接查询,被驱动表的执行计划这里会显示驱动表的关联字段,如果是条件使用了表达式或者函数,或者条件列发生了内部隐式转换,这里可能显示为func
9)、rows
这里是执行计划中估算的扫描行数,不是精确值
10)、extra
这个列可以显示的信息非常多,有几十种,常用的有
A:distinct:在select部分使用了distinc关键字
B:no tables used:不带from字句的查询或者From dual查询
C:使用not in()形式子查询或not exists运算符的连接查询,这种叫做反连接。即,一般连接查询是先查询内表,再查询外表,反连接就是先查询外表,再查询内表。
D:using filesort:排序时无法使用到索引时,就会出现这个。常见于order by和group by语句中
E:using index:查询时不需要回表查询,直接通过索引就可以获取查询的数据。
F:using join buffer(block nested loop),using join buffer(batched key accss):5.6.x之后的版本优化关联查询的BNL,BKA特性。主要是减少内表的循环数量以及比较顺序地扫描查询。
G:using sort_union,using_union,using intersect,using sort_intersection:
using intersect:表示使用and的各个索引的条件时,该信息表示是从处理结果获取交集
using union:表示使用or连接各个使用索引的条件时,该信息表示从处理结果获取并集
using sort_union和using sort_intersection:与前面两个对应的类似,只是他们是出现在用and和or查询信息量大时,先查询主键,然后进行排序合并后,才能读取记录并返回。
H:using temporary:表示使用了临时表存储中间结果。临时表可以是内存临时表和磁盘临时表,执行计划中看不出来,需要查看status变量,used_tmp_table,used_tmp_disk_table才能看出来。
I:using where:表示存储引擎返回的记录并不是所有的都满足查询条件,需要在server层进行过滤。查询条件中分为限制条件和检查条件,5.6之前,存储引擎只能根据限制条件扫描数据并返回,然后server层根据检查条件进行过滤再返回真正符合查询的数据。5.6.x之后支持ICP特性,可以把检查条件也下推到存储引擎层,不符合检查条件和限制条件的数据,直接不读取,这样就大大减少了存储引擎扫描的记录数量。extra列显示using index condition
J:firstmatch(tb_name):5.6.x开始引入的优化子查询的新特性之一,常见于where字句含有in()类型的子查询。如果内表的数据量比较大,就可能出现这个
K:loosescan(m..n):5.6.x之后引入的优化子查询的新特性之一,在in()类型的子查询中,子查询返回的可能有重复记录时,就可能出现这个
除了这些之外,还有很多查询数据字典库,执行计划过程中就发现不可能存在结果的一些提示信息
11)、filtered
使用explain extended时会出现这个列,5.7之后的版本默认就有这个字段,不需要使用explain extended了。这个字段表示存储引擎返回的数据在server层过滤后,剩下多少满足查询的记录数量的比例,注意是百分比,不是具体记录数。
### Mysql各种存储引擎
数据库中的存储引擎其实是对使用了该引擎的表进行某种设置,数据库中的表设定了什么存储引擎,那么该表在数据存储方式、数据更新方式、数据查询性能以及是否支持索引等方面就会有不同的“效果”。在MySQL数据库中存在着多种引擎(不同版本的MySQL数据库支持的引擎不同),熟悉各种引擎才能在软件开发中应用引擎,从而开发出高性能的软件,MySQL数据库中的引擎有哪些呢?一般来说,MySQL有以下几种引擎:ISAM、MyISAM、HEAP(也称为MEMORY)、CSV、BLACKHOLE、ARCHIVE、PERFORMANCE_SCHEMA、InnoDB、 Berkeley、Merge、Federated和Cluster/NDB等,除此以外我们也可以参照MySQL++ API创建自己的数据库引擎。下面逐次介绍一下各种引擎:
ISAM
该引擎在读取数据方面速度很快,而且不占用大量的内存和存储资源;但是ISAM不支持事务处理、不支持外来键、不能够容错、也不支持索引。该引擎在包括MySQL 5.1及其以上版本的数据库中不再支持。
MyISAM
该引擎基于ISAM数据库引擎,除了提供ISAM里所没有的索引和字段管理等大量功能,MyISAM还使用一种表格锁定的机制来优化多个并发的读写操作,但是需要经常运行OPTIMIZE TABLE命令,来恢复被更新机制所浪费的空间,否则碎片也会随之增加,最终影响数据访问性能。MyISAM还有一些有用的扩展,例如用来修复数据库文件的MyISAMChk工具和用来恢复浪费空间的 MyISAMPack工具。MyISAM强调了快速读取操作,主要用于高负载的select,这可能也是MySQL深受Web开发的主要原因:在Web开发中进行的大量数据操作都是读取操作,所以大多数虚拟主机提供商和Internet平台提供商(Internet Presence Provider,IPP)只允许使用MyISAM格式。
MyISAM类型的表支持三种不同的存储结构:静态型、动态型、压缩型。
静态型:指定义的表列的大小是固定(即不含有:xblob、xtext、varchar等长度可变的数据类型),这样MySQL就会自动使用静态MyISAM格式。使用静态格式的表的性能比较高,因为在维护和访问以预定格式存储数据时需要的开销很低;但这种高性能是以空间为代价换来的,因为在定义的时候是固定的,所以不管列中的值有多大,都会以最大值为准,占据了整个空间。
动态型:如果列(即使只有一列)定义为动态的(xblob, xtext, varchar等数据类型),这时MyISAM就自动使用动态型,虽然动态型的表占用了比静态型表较少的空间,但带来了性能的降低,因为如果某个字段的内容发生改变则其位置很可能需要移动,这样就会导致碎片的产生,随着数据变化的增多,碎片也随之增加,数据访问性能会随之降低。
对于因碎片增加而降低数据访问性这个问题,有两种解决办法:
a、尽可能使用静态数据类型;
b、经常使用optimize table table_name语句整理表的碎片,恢复由于表数据的更新和删除导致的空间丢失。如果存储引擎不支持 optimize table table_name则可以转储并 重新加载数据,这样也可以减少碎片;
压缩型:如果在数据库中创建在整个生命周期内只读的表,则应该使用MyISAM的压缩型表来减少空间的占用。
HEAP(也称为MEMORY)
该存储引擎通过在内存中创建临时表来存储数据。每个基于该存储引擎的表实际对应一个磁盘文件,该文件的文件名和表名是相同的,类型为.frm。该磁盘文件只存储表的结构,而其数据存储在内存中,所以使用该种引擎的表拥有极高的插入、更新和查询效率。这种存储引擎默认使用哈希(HASH)索引,其速度比使用B-+Tree型要快,但也可以使用B树型索引。由于这种存储引擎所存储的数据保存在内存中,所以其保存的数据具有不稳定性,比如如果mysqld进程发生异常、重启或计算机关机等等都会造成这些数据的消失,所以这种存储引擎中的表的生命周期很短,一般只使用一次。
CSV(Comma-Separated Values逗号分隔值)
使用该引擎的MySQL数据库表会在MySQL安装目录data文件夹中的和该表所在数据库名相同的目录中生成一个.CSV文件(所以,它可以将CSV类型的文件当做表进行处理),这种文件是一种普通文本文件,每个数据行占用一个文本行。该种类型的存储引擎不支持索引,即使用该种类型的表没有主键列;另外也不允许表中的字段为null。
BLACKHOLE(黑洞引擎)
该存储引擎支持事务,而且支持mvcc的行级锁,写入这种引擎表中的任何数据都会消失,主要用于做日志记录或同步归档的中继存储,这个存储引擎除非有特别目的,否则不适合使用。详见博客《BlackHole 存储引擎》
ARCHIVE
该存储引擎非常适合存储大量独立的、作为历史记录的数据。区别于InnoDB和MyISAM这两种引擎,ARCHIVE提供了压缩功能,拥有高效的插入速度,但是这种引擎不支持索引,所以查询性能较差一些。
PERFORMANCE_SCHEMA
该引擎主要用于收集数据库服务器性能参数。这种引擎提供以下功能:提供进程等待的详细信息,包括锁、互斥变量、文件信息;保存历史的事件汇总信息,为提供MySQL服务器性能做出详细的判断;对于新增和删除监控事件点都非常容易,并可以随意改变mysql服务器的监控周期,例如(CYCLE、MICROSECOND)。
InnoDB
该存储引擎为MySQL表提供了ACID事务支持、系统崩溃修复能力和多版本并发控制(即MVCC Multi-Version Concurrency Control)的行级锁;该引擎支持自增长列(auto_increment),自增长列的值不能为空,如果在使用的时候为空则自动从现有值开始增值,如果有但是比现在的还大,则直接保存这个值; 该引擎存储引擎支持外键(foreign key) ,外键所在的表称为子表而所依赖的表称为父表。该引擎在5.5后的MySQL数据库中为默认存储引擎。
Berkeley(BDB)
该存储引擎支持COMMIT和ROLLBACK等其他事务特性。该引擎在包括MySQL 5.1及其以上版本的数据库中不再支持。
Merge
该引擎将一定数量的MyISAM表联合而成一个整体。参见博客《MySQL Merge存储引擎》
Federated
该存储引擎可以不同的Mysql服务器联合起来,逻辑上组成一个完整的数据库。这种存储引擎非常适合数据库分布式应用。
Cluster/NDB
该存储引擎用于多台数据机器联合提供服务以提高整体性能和安全性。适合数据量大、安全和性能要求高的场景。
### String,StringBuffer,StringBuild的区别
String字符串常量
StringBuffer字符串变量(线程安全)
StringBuild字符串变量(非线程安全)
1. 首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String
2. 再来说线程安全
在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的
如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。
总结:
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
### 开发中建造者模式有哪些
建造者模式:
```java
public interface Sender {
public void Send();
}
public class Builder {
private List list = new ArrayList();
public void produceMailSender(int count){
for(int i=0; i |
| hashCode() | int |
| toString() | String |
| clone() | Object |
| equals(Object) | boolean |
| wait() | void |
| notify() | void |
| notifyAll() | void |
### mysql锁表机制
### 如何解决mysql读写冲突
### Transactional
### spring和springmvc常用注解
#### spring常用注解
- @Component
是所有受Spring 管理组件的通用形式,@Component注解可以放在类的头上,@Component不推荐使用。。
- @Controller
标注一个控制器组件类。
- @Service
标注一个业务逻辑组件类。
- @Repository
标注一个DAO组件类。
- @Bean
@Bean是一个方法级别上的注解,主要用在@Configuration注解的类里,也可以用在@Component注解的类里。添加的bean的id为方法名
定义bean,下面是@Configuration里的一个例子
```java
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
```
这个配置就等同于之前在xml里的配置
```
```
#### springmvc常用注解
- @Autowired:按类型注入
- @Resource(默认按名称注入)
@Resource(name="dataSource")
@Resource(type=DataSource.class)
- @RequestMapping
- @RequestParam(获取请求参数的值)
```java
@RestController
public class HelloController {
@RequestMapping(value="/hello",method= RequestMethod.GET)
public String sayHello(@RequestParam("id") Integer id){
return "id:"+id;
}
}
```
- @PathVaribale(获取url中的数据)
```java
@RestController
public class HelloController {
@RequestMapping(value="/hello/{id}",method= RequestMethod.GET)
public String sayHello(@PathVariable("id") Integer id){
return "id:"+id;
}
}
```
- @ResponseBody(返回类型为json)
### spring中bean是单利还是多例
单例的
### Spring中bean的生命周期
在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一个实例,而不是每次都产生一个新的对象使用Singleton模式产生单一实例,对单线程的程序说并不会有什么问题,但对于多线程的程序,就必须注意安全(Thread-safe)的议题,防止多个线程同时存取共享资源所引发的数据不同步问题。
然而在spring中 可以设定每次从BeanFactory或ApplicationContext指定别名并取得Bean时都产生一个新的实例:例如:
在spring中,singleton属性默认是true,只有设定为false,则每次指定别名取得的Bean时都会产生一个新的实例
一个Bean从创建到销毁,如果是用BeanFactory来生成,管理Bean的话,会经历几个执行阶段:
### 中断线程
```java
public void Thread.interrupt();
```
### wait/notify/notifyAll
- wait()、notify/notifyAll() 方法是Object的本地final方法,无法被重写
- wait()使当前线程阻塞,前提是 必须先获得锁,一般配合synchronized 关键字使用,即,一般在synchronized 同步代码块里使用 wait()、notify/notifyAll() 方法
- notify/notifyAll() 的执行只是唤醒沉睡的线程,而不会立即释放锁,锁的释放要看代码块的具体执行情况(不是按线程优先级来唤醒)
- notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。notifyAll 会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现。如果当前情况下有多个线程需要被唤醒,推荐使用notifyAll 方法。比如在生产者-消费者里面的使用,每次都需要唤醒所有的消费者或是生产者,以判断程序是否可以继续往下执行
- wait() 需要被try catch包围,中断也可以使wait等待的线程唤醒
### while与do-while
while判断条件是否满足如果不满足执行while后面的代码,如果满足则执行while里面的代码,直到不满足while条件时才执行while后面的代码
do-while先执行do里面的代码,再判断while是否满足,如果满足继续执行do里面的代码,直到不满足while条件时,do里面的代码将再执行,而继续执行do-while后面的代码
### synchronized
#### 生产-消费多线程安全案例
```java
import java.util.ArrayList;
import java.util.List;
/**
* 多线程安全性,生产者与消费者案例
* synchronized同步关键字的使用
* 放在方法上时,锁为synchronized修饰方法所在的那个对象
*/
public class Plate {
// 容器
List

"); document.write("薪水:" + s.sal + "
"); ``` #### 浏览器对象 window,document,status,location,history… ```javascript function myrefresh(){ window.history.go(0); } ``` #### ActiveX对象 ActiveXObject("Microsoft.XMLHTTP")… ### 初始化js函数方式 1 浏览器对象调用 ```javascript window.onload=function(){ alert(0); //var inputs = document.getElementsByTagName("input"); //alert(inputs); } ``` 2 jquery对象调用 ```javascript $(function(){ alert(0); }) ``` 3 写到标签中 ```javascript ``` ### javascript中获取标签元素的方式有哪些 #### getElementById document.getElementById('demo') //demo是元素对应的ID #### getElementsByTagName document.getElementsByTagname('li') //li是标签的名字 需要注意的是,该方法除了能被document对象调用之外,还可以被普通的元素调用。示例如下: var demo = document.getElementById('demo'); var lis = demo.getElementsByTagname('li'); #### getElementsByClassName 除了通过指定标签获取元素外,DOM还提供了getElementsByClassName方法来获取指定class名的元素。不过由于该方法比较新,较老的浏览器还不支持,比如IE6。不过我们可以通过hack方式来弥补老浏览器缺陷。该方法调用的方式如下所示: document.getElementsByClassName('demo') //demo为元素指定的class名 和getElementsByTagname一样, 该方法除了能被document对象调用之外,还可以被普通的元素调用。 对于比较老的浏览器,比如IE6、7我们可以通过下面的hack方式来实现: ```javascript function getElementsByClassName(node,classname){ if(node.getElementsByClassName) { return node.getElementsByClassName(classname); }else { var results = []; var elems = node.getElementsByTagName("*"); for(var i = 0; i < elems.length; i++){ if(elems[i].className.indexOf(classname) != -1){ results[results.length] = elems[i]; } } return results; } } ``` ### js中操作标签的class属性的关键字是什么 JavaScript中使用e.getAttribute('属性名')来取得属性的值,并且用e.setAttribute('属性名', '值')来设置属性值。 由于class属于JavaScript保留值,因此当我们要操作元素的class属性值时,直接使用e.getAttribute('class')和e.setAttribute('class', 'value')可能会遭遇浏览器兼容性问题 以下列表说明了上文提及的三种做法的浏览器兼容性测试: • e.className 能在IE、Mozilla(Firefox)、Opera和Safari正确运行 • e.getAttribute('class')和e.setAttribute('class', 'value') 能在Mozilla(Firefox)和Opera中正确运行,在IE和Safari中则不能使用。 • e.getAttribute('className') 在IE和Opera中正确运行,在Mozilla(Firefox)和Safari中则不能使用。 ### 写出JavaScript后退到前一个页面的操作,与在浏览器上点击后退按钮相同 ```html
这是第一个页面
下一个页面 ``` ```html
这是第二个页面
``` ### ajax AJAX 是 Asynchronous JavaScript And XML 的首字母缩写。 AJAX 并不是一种新的编程语言,而仅仅是一种新的技术,它可以创建更好、更快且交互性更强的 web 应用程序。 AJAX 使用 JavaScript 在 web 浏览器与 web 服务器之间来发送和接收数据。 通过在幕后与 web 服务器交换数据,而不是每当用户作出改变时重载整个 web 页面,AJAX 技术可以使网页更迅速地响应。 ### servlet返回字符串到页面获取字符串 在一个servlet中: ```java response.setContentType("text/html;charset=UTF-8"); PrintWriter pw = response.getWriter(); pw.write(tip);//写出到浏览器 pw.flush(); pw.close(); ``` ### ajax发送post请求 现有请求地址/getData,请求参数为id,参数值为1,请用jQuery通过Ajax发送POST请求,获取json数据,打印到控制台 action类 ```java import javax.servlet.http.HttpServletRequest; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class GetDataAction extends ActionSupport{ private User user; public String getData(){//不能传参 HttpServletRequest request = ServletActionContext.getRequest(); System.out.println("进入action"); String id = request.getParameter("id"); user = new User(); user.setId(id); user.setUserName("张三"); System.out.println(user); return SUCCESS; } public User getUser() { return user; } } ``` jsp页面 ```html <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
编号 | 标题 | 内容 |
---|---|---|
${article.id} | ${article.title} | ${article.content} |
编号 | 标题 | 内容 |
---|---|---|
${article.id} | ${article.title} | ${article.content} |
【首页】
|