2018-04-13Java编程夯实学习心得(3)
构建工具maven的使用-->log4j日志处理-->解析properties文件--> xml文档-->dom4j解析-->反射-->jdbc数据库技术操作数据库-->junit测试-->断言
-- 37 Maven
作用:项目构建工具,是目前大部分企业在做项目时首选的项目构建管理工具(也有一部分企业在用Ant)
特点:
1,可以使用maven来编译你的代码
2,项目打包也可以使用maven来完成
3,maven可以实现项目模块化管理
4,maven可以在线管理依赖,项目依赖也很方便获取
5,maven提供了一些丰富的插件,方便项目持续集成
maven集成到eclipse
1,高版本的eclipse一般都有集成maven
如果eclipse默认没有集成maven,则需要下载集成包
2,可以在eclipse里设置maven的仓库位置。
所谓的仓库就是保存项目依赖jar包的目录
查看eclipse是否有maven
window-preferences-maven-user settings(设置本地仓库地址)
空白处右键-maven
-- maven项目的创建
Group id分组
Artifact id项目包名(简单理解为jar包)
Version版本
packaging打包方式
-- maven 中央仓库
地址:https://mvnrepository.com/artifact/org.hamcrest
maven这个项目维护的一个网站,在这个上面维护了非常多开元项目的jar包
并且维护了每个jar包的版本,便于项目开发着们去下载使用。
-- maven本地仓库
通过maven拿下来的jar包会被保存在用户本地电脑的某个目录,
这个是用过maven拍照来指定的。
1.如果用户的eclipse是继承了maven的,那么在eclipse中可以设置默认
setting.xml中的本地仓库位置
去中央仓库拿jar包,保存到本地仓库
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.4.0</version>
</dependency>
-- 38maven项目结构
src/main/java, 一般开发人员写代码目录
src/main/resources,开发人员放项目资源文件的目录
src/test/java,放测试人员代码的目录
src/test/resources,放测试资源文件的目录
jre system library,
maven dependencies,通过maven拿下来的项目依赖包存放目录
target,存放构建后文件的目录
-- log4j
日志:在项目中,不管是开发人员写代码还是测试人员写的测试代码一般都需要做一些日志来记录项目的行为
以便更好的跟踪项目中的一些交互和问题
log4j是一个日志框架,配置简单,功能强大,在项目中用它来记录日志是很方便的
-- 下载log4jjar包
在maven项目中添加依赖
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
-- 配置log4j,建立log4j.properties文件
建立文件,支持utf-8格式log4j.properties
###根logger设置###
log4j.rootLogger = INFO,console,file
### 输出信息到控制台###
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = [%p] %d{yyyy-MM-dd HH:mm:ss} method: %l----%m%n
###输出INFO 级别以上的日志文件设置###
log4j.appender.file = org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File = E:/log/web.log
log4j.appender.file.Append = true
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} method: %l - [ %p ]----%m%n
-- 例子
public class LogDemo {
private static Logger logger=Logger.getLogger(LogDemo.class);//创建对象
public static void main(String[] args) {
logger.info("测试开始,记录info级别的日志");
logger.info("完成1/0的除法运算");
try{
int result=1/0;
}catch(Exception e){
logger.error("报错了,被除数不能为0");
}finally{
logger.info("测试日志结束");
}
}
}
-- 参数
[%p] %d{yyyy-MM-dd HH:mm:ss} method: %l----%m%n
%p,日志等级,debug/info/warn/error/fatal
%d,日志时间
{yyyy-MM-dd HH:mm:ss}指定日志时间格式
method,照常显示
%l,路径,类名包名线程和代码行数
---,照常显示
%m,显示日志内容信息
%n,回车换行符
-- properties文件
properties文件作为项目中比较常用的一种配置文件,它的作用是可以将系统依赖
的一些数据通过配置时间与代码分离解耦
特点:以键值对的形式保存数据
-- 解析properties文件
Properties properties=new Properties();//创建properties文件对象
File file=new File("log4j.properties");//指定properties文件路径
InputStream inStream=new FileInputStream(file);//字节流对象
properties.load(instream);//加载文件内容
注意:
load方法需要一个inputstream流对象
例子
public class PropertiesDemo {
public static void main(String[] args) throws FileNotFoundException, IOException {
Properties properties=new Properties();//创建对象
properties.load(new FileInputStream("src/test/resources/log4j.properties"));
//加载文件内容到对象,从项目的路径查找文件内容src/test/resources
// properties.load(PropertiesDemo.class.getResourceAsStream("/log4j.properties"));
//第二种,加载文件内容到对象,类名.class.getresourasstream从当前classpath文件路径获取文件
// properties.load(new FileInputStream(new File("log4j.properties")));
//第一种,当log4j.properties文件在当前项目底下时,new File("log4j.properties")从当前项目下找文件
String value1=(String)properties.get("log4j.rootLogger");
String value2=(String)properties.get("log4j.appender.console");
//根据key值查找value值
System.out.println(value1);
System.out.println(value2);
}
}
--读取项目文件到inputstream输入流
有一个test.properties文件,它在项目中的位置一般是以下情况
1,项目根路径下
inputstream is=new FileInputStream(new File("test.properties"));
表示从当前项目下找文件
作业
1用递归的方法求和
public class SumDemo {
public static void main(String[] args) {
System.out.println(f(100));//用递归的方法求和
}
static int f(int n){
if(n==1){
return 1;
}else{
return f(n-1)+n;//循环和前一个数求和
}
}
}
2//创建文件E:\\aa\\bb\\test.txt
public class FileDemo {
public static void main(String[] args) throws IOException {
String path="E:\\aa\\bb\\test.txt";//文件地址
File file =new File(path);//创建对象
if(!file.exists()){//判断是否存在文件
String path1=path.substring(0,path.lastIndexOf("\\"));//拿到目录,创建目录对象并且先建立目录
File dir=new File(path1);//创建目录的对象
dir.mkdirs();//先创建目录
file.createNewFile();//在创建文件
}
}
}
-- 41xml概念
XML:Extensible Markup Language扩展性标记语言
特点:可扩展性,在遵循xml语法的前提下支持自定义和修改。
标记语言,意味着也是以类似于html中的标签来定义的文档
xml在项目中的使用更多的是作为数据载体而出现的。
xml和json都是一种数据交互格式
-- xml文档结构
1,xml文档结构和html类似,也是一种树形结构,从上往下扩展
2,父,子以及同胞等术语用于描述元素之间的关系。父元素拥有子元素,相同层级上的子元素称为同胞
3,所有元素都可以有文本内容和属性
xml与html的区别
xml是作为数据传输的工具,是一种数据载体
html是数据展示的工具
-- 语法
XML声明
<?xml version="1.0encoding=utf-8"?>
根元素
xml必须包含根元素,它是所有其他元素的父元素,比如以下实例中的person
<person>
<name>张三</name>
<age>18</age>
</person>
元素的属性值要用双引号""
注释
<!--注释-->
-- dom4j解析技术
<?xml version="1.0encoding=utf-8"?>
<student>
<name>张三</name>
<age>18</age>
<gender>男</gender>
</student>
1,添加依赖:dom4j
2,创建解析器SaxReader对象
3,获取document对象
4,获取根元素
5,获取根元素下的子元素
public static List<Student> read() throws DocumentException {
//创建解析器SaxReader对象;
//读取xml文件返回document对象;read(inputstream in)调用输入流,路径(name)
//通过文档对象获取根元素;getRootElement
//通过根元素创建子元素;
//封装对象,属性
SAXReader reader=new SAXReader();
Document document=reader.read(ArrayListDemo.class.getResourceAsStream("/student.xml"));
Element root=document.getRootElement();
List<Element>students=root.elements();//遍历根元素
Student student=new Student();
List<Student>list=new ArrayList<Student>();//保存所有的student子元素到集合并且返回
-- 常用的API
创建解析器:SaxReader reader=new SaxReader();
解析器读取文件获得文档对象:Document document=reader.read(file);
文档对象获取根节点:document.getRootElement();
elements():获取当前元素下的所有子元素
elements("xx")获取当前元素下元素名为xx的所有子元素
elementIterator():获取元素迭代器
attribute(index):获取元素指定索引位置上的属性的值
attribute("xx"):获取元素的xx属性的值
attributeIterator():获取属性迭代器
-- 43复习
集合:数据的增删改差
list-->arraylist(有序,可重复)
--例子解析xml
import java.util.ArrayList;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.ningmengban.properties.Student;
import com.ningmengban.properties.XmlReader;
public class ArrayListDemo {
public static void main(String[] args) throws DocumentException {
List<Student>students=XmlReader.read();
for (Student student : students) {
System.out.println(student);
}
}
public static List<Student> read() throws DocumentException {
//创建解析器SaxReader对象;
//读取xml文件返回document对象;read(inputstream in)调用输入流,路径(name)
//通过文档对象获取根元素;getRootElement
//通过根元素创建子元素;
//封装对象,属性
SAXReader reader=new SAXReader();
Document document=reader.read(ArrayListDemo.class.getResourceAsStream("/student.xml"));
Element root=document.getRootElement();
List<Element>students=root.elements();//遍历根元素
Student student=new Student();
List<Student>list=new ArrayList<Student>();//保存所有的student子元素到集合并且返回
for (Element element : students) {
List<Element>elements=element.elements();//遍历子元素
for (Element element2 : elements) {
if(element2.getName().equals("name")){
student.setName(element2.getText());
}else if(element2.getName().equals("age")){
student.setAge(Integer.parseInt(element2.getText()));
}else if(element2.getName().equals("gender")){
student.setGender(element2.getText());
}
}
}list.add(student);
return list;
}
}
简化上面代码,通过反射获取属性(当方法名过多并且属性相同时)
for (Element element : students) {
Class<Student>clazz=Student.class;
Student student=clazz.newInstance();
List<Element>elements=element.elements();
for (Element element2 : elements) {//通过反射获取子元素
String name=element2.getName();
String methodname="set"+(name.charAt(0)+"").toUpperCase()+name.substring(1);
System.out.println("方法名:"+methodname);
Method method=null;
if ("age".equals(name)) {
method = clazz.getMethod(methodname, int.class);
method.invoke(student, Integer.valueOf(element2.getText()));
} else {
method = clazz.getMethod(methodname, String.class);
method.invoke(student, element2.getText());
}
}list.add(student);
}
-- 45/46什么是反射
反射就是根据类的字节码class文件获取一个类的细节,包括构建
出来的对象,通过对象去调用方法,访问属性
-- 反射的思想
如果对象的属性值要支持可扩展
-- 反射的实现
1,获取字节码
2,通过字节码去创建对象
3,通过字节码获取到可以调用到的方法
4,调用method
-- 例子
public class ReflectDemo {
public static void main(String[] args) throws Exception {
ReflectDemo demo = new ReflectDemo();
demo.test();
}
public void test() throws Exception {
// 获取对象类型的字节码,三种方法
Class <Student>clazz1 = Student.class;
// Student student =new Student();
// Class clazz2 = this.getClass();
// Class clazz3=Class.forName("com.ningmengban.reflect.Student");
// System.out.println("类名:"+clazz1.getName());//通过字节码获取包名类名
// System.out.println("是否是接口:"+clazz1.isInterface());
// System.out.println("包名:"+clazz1.getPackage().getName());
// System.out.println("父类包名:"+clazz1.getSuperclass().getName());
// Constructor<Student>[]constructors=(Constructor<Student>[])clazz1.getConstructors();
// //Constructor构造函数,强制转换(Constructor<Student>[])
// for (Constructor<Student> constructor : constructors) {
// System.out.println("构造函数的名字:"+constructor.getName());
// Parameter[]parameters=constructor.getParameters();
// System.out.println("构造函数参数个数:"+constructor.getParameterCount());
// System.out.println("构造函数的修饰符:"+constructor.getModifiers());
// for (Parameter parameter : parameters) {
// System.out.println("参数的名字:"+parameter.getName());
// System.out.println("参数的类型"+parameter.getType());
// }
// }
// Field[]fields=clazz1.getDeclaredFields();
// for (Field field : fields) {
// System.out.println("字段名:"+field.getName());
// System.out.println("字段类型:"+field.getType());
// System.out.println("修饰符:"+field.getModifiers());
// }
// System.out.println("根据参数获取当前类的字段:"+ clazz1.getField("age"));
// Method []methods=clazz1.getMethods();
// for (Method method : methods) {
// System.out.println("方法名:"+method.getName());
// System.out.println("返回值类型:"+method.getReturnType());
// System.out.println("方法的修饰符:"+method.getModifiers());
// System.out.println("参数个数:"+method.getParameterCount());
// Class[]classes=method.getParameterTypes();
// for (Class class1 : classes) {
// System.out.println(class1);
// for(int i=0;i<classes.length;i++){
// System.out.println("第"+(i+1)+"参数类型"+classes[i]);
// }
// }
// 构建对象,两种方法
Student student1=clazz1.newInstance();//默认构造器构建对象,默认构建函数
Constructor constructor=clazz1.getConstructor(String.class,int.class,String.class);
Student student2=(Student) constructor.newInstance("张三",20,"女");//根据传入参数类型,在根据构造器构建对象,带参构造函数
// 通过字节码可以调用函数
Method method1=clazz1.getDeclaredMethod("setName", String.class);
// 调用函数
method1.invoke(student1, "小明");
Method method2=clazz1.getDeclaredMethod("setGender", String.class);
method2.invoke(student1, "男");
Method method3=clazz1.getDeclaredMethod("setAge", int.class);
method3.invoke(student1, 20);
System.out.println(student1);
System.out.println(student2);
}
}
-- 47jdbc数据库技术操作数据库
-- 驱动包
要使用jdbc技术操作数据库,必须根据对应的数据库类型选择合适的驱动包
我们的项目数据库为mysql,所以我们会用到mysql的驱动包:mysql-connector-java
-- 环境搭建
添加依赖:mysql-connector-java
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
-- 操作数据库的步骤
1,加载驱动程序
Class.forName("com.mysql.jdbc.Driver");
2,获得数据库链接(连接上数据库)
Connection conne=DriverManager.getConnection(URL,USER,PASSWORD);
3,获取PreparedStatement对象(防注入)
conn.prepareStatement(sql);
4,执行查询,返回ResultSet(结果集)
ResultSet rst=stmt.executeQuery();
5,执行查询
ResultSet=stmt.executeQuery();
-- 代码优化篇:单例模式
1,解耦
2,封装
3,单例
例子
1 配置文件properties文件
url = jdbc:mysql://119.23.241.154:3306/lmcanon
user = test
password = test
2封装
public class JDBCUtil {
public static Properties properties;
// 静态代码块,只执行一次
static {
properties = new Properties();
try {
properties.load(JDBCUtil.class.getResourceAsStream("/jdbc.properties"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static ResultSet query(String url, String user, String password, String sql, Object... values)
throws Exception {
// 加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 获取数据库链接
Connection connection = DriverManager.getConnection(url, user, password);
// 获取prepareStatement对象
PreparedStatement statement = connection.prepareStatement(sql);
for (int i = 1; i <= values.length; i++) {
statement.setObject(i, values[i - 1]);
}
// 执行查询
ResultSet resultSet = statement.executeQuery();
// 取数据
return resultSet;
}
}
3.调用method
public class JDBCDemo3 {
public static void main(String[] args) throws Exception {
String url=JDBCUtil.properties.getProperty("url");
String user=JDBCUtil. properties.getProperty("user");
String password=JDBCUtil. properties.getProperty("password");
String sql="select*from member where mobilephone=?";
Object[]objects=new Object[]{"13517315120"};
ResultSet resultSet = JDBCUtil.query(url, user, password,sql,objects);
if (resultSet.next()) {
String value = resultSet.getString("nickname");
System.out.println(resultSet.getString(4));
System.out.println(value);
}
}
}
-- junit
依赖包
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
-- 编写单元测试类
常用注解
1,@Test :表明这是一个测试方法
2,@Before:每执行一个测试方法前都会先执行被标注了此注解的方法
3,@After:每执行一个测试方法后都会执行被标注了此注解的方法
4,@BeforeClass:测试用例初始化时执行被@BeforeClass标注的方法,只会执行一次
5,@AfterClass:当所有测试用例执行完毕后,执行进行收尾工作,也就是执行被@afterclass标注的方法
只会执行一次
-- 断言
assertEquals(a,b);判断两数据是否一致,如果一致则表示测试通过,否则表示不通过,抛出断言错误
assertNotEquals(a,b);判断两数据是否不一致,如果不一致则表示测试通过,否则表示不通过,抛出断言错误
assertNull(...);断言某数据是否为空,如果为空则表示测试通过,否则表示不通过,抛出断言错误
assertNotNull(...);断言某数据是否非空,如果非空则表示测试通过,否则表示不通过,抛出断言错误
assertFlase(...);断言某布尔类型数据是否为flase,如果为flase则表示测试通过,否则表示不通过,抛出断言错误
assertTure(...);断言某布尔类型数据是否为true,如果为true则表示测试通过,否则表示不通过,抛出断言错误
例子
1方法
public class Calulator {
public int jiafa(int a,int b){
return a+b;
}
public int jianfa(int a,int b){
return a-b;
}
public int chenfa(int a,int b){
return a*b;
}
public int chufa(int a,int b){
return a/b;
}
}
2执行测试类
public class CalulatorTest {
@Test
public void testjiafa(){
Calulator calulator=new Calulator();
int actual=calulator.jiafa(2, 3);//设置值
int expected=5;//期望值
Assert.assertEquals(expected, actual);//断言,做比较
}
@Test
public void testjianfa(){
Calulator calulator=new Calulator();
int actual=calulator.jianfa(2, 3);
int expected=-1;
Assert.assertEquals(expected, actual);
}
@Test
public void testchenfa(){
Calulator calulator=new Calulator();
int actual=calulator.chenfa(2, 3);
int expected=6;
Assert.assertEquals(expected, actual);
}
@Test
public void testchufa(){
Calulator calulator=new Calulator();
int actual=calulator.chufa(2, 3);
int expected=0;
Assert.assertEquals(expected, actual);
}
}
-- 打包测试
使用@RunWith@Suite定义打包类,是测试类全部执行打包测试
例子:
@RunWith(Suite.class)
@Suite.SuiteClasses({
Test1.class,//测试类
Test2.class,//测试类
CalulatorTest.class//测试类
})
public class PackageTest {
}