Welcome
admin
admin

2025-06-18 18:14:42

世界杯误判
3327 330

大家好,又见面了,我是你们的朋友全栈君。

SSM框架(白痴都看完都会)文章目录SSM框架(白痴都看完都会)介绍SSM框架<原理>一、什么是SSM框架? 1.Spring2.Spring MVC3.Mybatis (核心是SqlSession)二、代码实战 1.创建配置工程2.代码实战(查询记录数)3.代码实战(增加)3.代码实战(增删改查,模糊精确查询集合)介绍SSM框架<原理>一、什么是SSM框架?SSM框架是spring、spring MVC 、和mybatis框架的整合,是标准的MVC模式。标准的SSM框架有四层,分别是dao层(mapper),service层,controller层和View层。使用spring实现业务对象管理,使用spring MVC负责请求的转发和视图管理,mybatis作为数据对象的持久化引擎。

1)持久层:dao层(mapper)层

作用:主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此。

Dao层首先设计的是接口,然后再Spring的配置文件中定义接口的实现类。然后可以在模块中进行接口的调用来进行数据业务的处理。(不在关心接口的实现类是哪个类)数据源的配置以及有关数据库连接的参数都在Spring的配置文件中进行配置。2)业务层:Service层

作用:Service层主要负责业务模块的逻辑应用设计。

先设计接口然后再设计实类,然后再在Spring的配置文件中配置其实现的关联。(业务逻辑层的实现具体要调用到自己已经定义好的Dao的接口上)这样就可以在应用中调用Service接口来进行业务处理。建立好Dao之后再建立service层,service层又要在controller层之下,因为既要调用Dao层的接口又要提供接口给controller层。每个模型都有一个service接口,每个接口分别封装各自的业务处理的方法。3)表现层:Controller层(Handler层)

作用:负责具体的业务模块流程的控制。

配置也同样是在Spring的配置文件里面进行,调用Service层提供的接口来控制业务流程。业务流程的不同会有不同的控制器,在具体的开发中可以将我们的流程进行抽象的归纳,设计出可以重复利用的子单元流程模块。4)View层

作用:主要和控制层紧密结合,主要负责前台jsp页面的表示。

各层之间的联系

这里是引用

DAO层,Service层这两个层次都可以单独开发,互相的耦合度很低,完全可以独立进行,这样的一种模式在开发大项目的过程中尤其有优势,Controller,View层因为耦合度比较高,因而要结合在一起开发,但是也可以看作一个整体独立于前两个层进行开发。这样,在层与层之前我们只需要知道接口的定义,调用接口即可完成所需要的逻辑单元应用,一切显得非常清晰简单。

1.SpringSpring里面的IOC容器和AOP是我们平时使用最多的。

1)IOC(控制反转)

它可以装载bean,也是一种降低对象之间耦合关系的设计思想。(比如租房子。以前租房子需要一个房子一个房子找,费时费力,然后现在加入一个房屋中介,把你需要的房型告诉中介,就可以直接选到需要的房子,中介就相当于spring容器。)

2)AOP(面向切面)

是面向对象开发的一种补充,它允许开发人员在不改变原来模型的基础上动态的修改模型以满足新的需求,如:动态的增加日志、安全或异常处理等。AOP使业务逻辑各部分间的耦合度降低,提高程序可重用性,提高开发效率。

1.横切关注点:从每个方法中抽取出来的同一类非核心业务代码。

2.切面:封装横切信息点的类,每个关注点体现为一个通知方法。

3.通知:切面必须要完成的各个具体工作,也就是切面里的一个个方法。

4.目标:被通知的对象,也就是被通知方法所作用的对象。

5.代理:像目标对象应用通知之后所创建的代理对象。

6.连接点:横切关注点在程序代码中的具体体现,对应用程序执行的某个特定位置。(通俗来讲就是一个个的方法)

7.切入点:切入点就是定位连接点的方式。每个通知上的切入点表达式找到对应的连接点,执行通知之后连接点也就变成了切入点。

2.Spring MVC <复杂版>

1、 用户发送请求至前端控制器DispatcherServlet。

2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。

3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

4、 DispatcherServlet调用HandlerAdapter处理器适配器。

5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。

6、 Controller执行完成返回ModelAndView。

7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。

8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。

9、 ViewReslover解析后返回具体View。

10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。

11、 DispatcherServlet响应用户。

<简单版>

1.客户端发送请求到DispacherServlet(分发器)

2.由DispacherServlet控制器查询HanderMapping,找到处理请求的Controller

3.Controller调用业务逻辑处理后,返回ModelAndView

4.DispacherSerclet查询视图解析器,找到ModelAndView指定的视图

5.视图负责将结果显示到客户端

3.Mybatis (核心是SqlSession)mybatis是对jdbc的封装,它让数据库底层操作变的透明。mybatis的操作都是围绕一个sqlSessionFactory实例展开的。mybatis通过配置文件关联到各实体类的Mapper文件,Mapper文件中配置了每个类对数据库所需进行的sql语句映射。在每次与数据库交互时,通过sqlSessionFactory拿到一个sqlSession,再执行sql命令。

二、代码实战1.创建配置工程1)创建maven工程

2)创建目录

src——main下创建两个文件夹(Java和resources)。和main同级的创建一个test,test里面创建一个Java。3)配置工程

file——project structure——modules

4)创建包

在src——java下创建问价夹(XXX),(XXX)下创建entity,mapper,,service和util包。5)配置依赖

pom.xml加入依赖,一个是Mybatis的,一个是MySQL的。

代码如下(示例):

代码语言:javascript代码运行次数:0运行复制

org.mybatis

mybatis

3.5.1

mysql

mysql-connector-java

5.1.36

2.代码实战(查询记录数)1)设计数据库

1)创建实体类

在entity下new一个名为person的class

代码如下(示例):

代码语言:javascript代码运行次数:0运行复制public class Person {

private Integer Id;

private String name;

private String nickname;

private Integer age;

public Integer getId() {

return Id;

}

public void setId(Integer id) {

this.Id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getNickname() {

return nickname;

}

public void setNickname(String nickname) {

this.nickname = nickname;

}

public Integer getAge() {

return age;

}

public void setAge(Integer age) {

this.age = age;

}

@Override

public String toString() {

return "Person{" +

"Id=" + Id +

", name='" + name + '\'' +

", nickname='" + nickname + '\'' +

", age=" + age +

'}';

}

}2)Mapper接口

定义方法(实体名+Mapper)

在mapper下创建一个名为PersonMapper的interface

代码语言:javascript代码运行次数:0运行复制public interface PersonMapper {

//定义查询记录方法数

public Integer findCount();

}3)resources包

resources包下创建cn包cn包下创建kgc包kgc包下创建一个XML(这里的xml文件名与mapper接口名一致)

xml文件中有两个部分组成,一个是头部文件,一个是主体代码语言:javascript代码运行次数:0运行复制//头文件:

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">代码语言:javascript代码运行次数:0运行复制//查询映射标签(select):

(1)mapper叫根节点,根节点有个属性是namespace=””、namespace=””、的作用是映射我们mapper的全路径,在以后的使用中会自动映射成我们mapper的实现类

(2)select里面的Id=“”一般和我们PersonMapper里面的方法名保持一致

(3)返回值这里有一个专门的属性叫resultType=”java.lang.Integer”

(4)方法名和返回值都对应之后看有无参数,如果有要加上parameterType=””

4)写sql语句`

代码语言:javascript代码运行次数:0运行复制

5)配置主配置文件mybatis-config.xml`

在resources里新建mybatis-config.xml

代码语言:javascript代码运行次数:0运行复制

PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"

"http://ibatis.apache.org/dtd/ibatis-3-config.dtd">代码语言:javascript代码运行次数:0运行复制//根节点:爷爷

//子节点:爸爸

//爸爸天生有很多的孙子(这里可以配置很多个数据库,比如development1,development2等等)

//事务里面有一个类型type,可以配JDBC(JDBC利用的机制是数据库它的一个数据源的一个事务JDBC。可以允许不用数据库的事务)

//(dataSource属性,代表数据源,链接数据库。“POOLED”这里的连接池根据需要可以更改。)

//development2(一般企业里配一个开发环境,一个测试环境)

//

//

//

//

//

代码语言:javascript代码运行次数:0运行复制mybatis-config.xml完整代码:

PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"

"http://ibatis.apache.org/dtd/ibatis-3-config.dtd">

5)测试`

在test——Java包下新建一个名为TestMybatis的测试类

测试用例怎么写:测一个对象sqlSession,需要通过sqlSessionFactor()对象才能创建sqlSession。sqlSessionFactor()需要通过sqlSessionFactor()Builder()来创建出来。

先new一个SqlSessionFactoryBuilder(),得到一个返回值builder代码语言:javascript代码运行次数:0运行复制 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();获取我们的SqlSessionFactory,要用builder.上我们的builder()方法,通过流的形式传一个In的参数。通过Resources.getResourceAsStream(“”)读取我们的主配置文件才能调用我们的依赖信息,在这里抛异常。这里有一个返回值nputStream in(字节流),通过字节流就可以读取这时builder.build(in);得到哟个返回值就是SqlSessionFactory factory。得到SqlSessionFactory factory之后,根据图片的流程就要得到我们的SqlSession。factory.openSession()打开我们的Session,就可以得到我们的Session执行sql语句。sqlSession.getMapper(这里的mapper利用的是我们的一个反射机制,机制利用的时我们的一个接口)通过sqlSession.getMapper(PersonMapper.class)调用一个调用方法,得到一个返回值count输出对应的返回值关闭sqlsession代码语言:javascript代码运行次数:0运行复制public class TestMybatis {

@Test

public void testHelloWorld() throws IOException {

//1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息

InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

//2.实例化SqlSessionFactoryBuilder对象

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

//3.调用builder对象的builder()方法,获取SqlSessionFactory对象

SqlSessionFactory factory = builder.build(in);

//4.调用factory对象的openSession()方法,获取SqlSession对象

SqlSession sqlSession = factory.openSession();

//5.调用接口的方法

Integer count = sqlSession.getMapper(PersonMapper.class).findCount();

//6.输出对应的返回值count

System.out.println("count:" + count);

//7.关闭 SqlSession

sqlSession.close();

}

}3.代码实战(增加)PersionMapper

代码语言:javascript代码运行次数:0运行复制public interface PersonMapper {

//定义查询记录方法数

public Integer findCount();

//增加

public Integer addPerson(Person person);

}PersonMapper.xml

代码语言:javascript代码运行次数:0运行复制

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

insert into t_user(name,nickname,age) values(#{

name},#{

nickname},#{

age})

测试类

代码语言:javascript代码运行次数:0运行复制 @Test

public void testInsert() throws Exception {

//1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息

InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

//2.实例化SqlSessionFactoryBuilder对象

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

//3.调用builder对象的builder()方法,获取SqlSessionFactory对象

SqlSessionFactory factory = builder.build(in);

//4.调用factory对象的openSession()方法,获取SqlSession对象

SqlSession sqlSession = factory.openSession();

//5.调用接口的方法

Person p = new Person();

p.setName("李四");

p.setNickname("一个人的夜晚上");

p.setAge(22);

sqlSession.getMapper(PersonMapper.class).addPerson(p);

//6.提交实物,该行代码必须放在关闭sqlsession之前

sqlSession.commit();

sqlSession.close();

}3.代码实战(增删改查,模糊精确查询集合)完整工程代码

Person类

代码语言:javascript代码运行次数:0运行复制package cn.kgc.entity;

public class Person {

private Integer Id;

private String name;

private String nickname;

private Integer age;

public Integer getId() {

return Id;

}

public void setId(Integer id) {

this.Id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getNickname() {

return nickname;

}

public void setNickname(String nickname) {

this.nickname = nickname;

}

public Integer getAge() {

return age;

}

public void setAge(Integer age) {

this.age = age;

}

@Override

public String toString() {

return "Person{" +

"Id=" + Id +

", name='" + name + '\'' +

", nickname='" + nickname + '\'' +

", age=" + age +

'}';

}

}PersonMapper类

代码语言:javascript代码运行次数:0运行复制package cn.kgc.mapper;

import cn.kgc.entity.Person;

import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface PersonMapper {

//定义查询记录方法数

public Integer findCount();

//增加

public Integer addPerson(Person person);

//修改功能

public Integer updatePerson(Person person);

//删除功能

public Integer delById(Integer Id);

//删除功能2

public Integer delById2(Person person);

//查询对象

public Person findById(Integer Id);

//查询集合

public List findAll();

//模糊查询

public List findByName(String name);

//通过用户名和昵称 绝对查询

public List findByPerson(Person person);

//通过用户名和昵称 绝对查询2

public List findByPerson2(@Param("name")String name,@Param("nickname")String nickname);

//测试¥(不安全)符号和#(安全)的作用

public List findColList(@Param("colname")String colname);

}MybatisUtil类

代码语言:javascript代码运行次数:0运行复制package cn.kgc.util;

import org.apache.ibatis.io.Resources;

import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;

import java.io.InputStream;

public class MytabisUtil {

private static SqlSessionFactory factory = null;

static {

try {

InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

factory = builder.build(in);

}catch (IOException e){

e.printStackTrace();

}

}

//获取SqlSession对象

public static SqlSession getSqlSession(){

SqlSession sqlSession = null;

if(factory!=null){

sqlSession = factory.openSession();

}

return sqlSession;

}

}PersonMapper.xml

代码语言:javascript代码运行次数:0运行复制

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

insert into t_user(name,nickname,age) values(#{

name},#{

nickname},#{

age})

update t_user set name=#{

name},nickname=#{

nickname},age=#{

age} where Id = #{

Id}

delete from t_user where id = #{

Id}

delete from t_user where id = #{

Id}

jdbc.properties(配置文件)

代码语言:javascript代码运行次数:0运行复制driver=com.mysql.jdbc.Driver

url=jdbc:mysql://localhost:3306/db_202125

username=root

password=123mybatis-config.xml

代码语言:javascript代码运行次数:0运行复制

PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"

"http://ibatis.apache.org/dtd/ibatis-3-config.dtd">

TestMybatis类

代码语言:javascript代码运行次数:0运行复制import cn.kgc.entity.Person;

import cn.kgc.mapper.PersonMapper;

import cn.kgc.util.MytabisUtil;

import jdk.internal.util.xml.impl.Input;

import org.apache.ibatis.io.Resources;

import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import org.junit.Test;

import java.io.IOException;

import java.io.InputStream;

import java.util.List;

public class TestMybatis {

@Test

public void testHelloWorld() throws IOException {

//1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息

InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

//2.实例化SqlSessionFactoryBuilder对象

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

//3.调用builder对象的builder()方法,获取SqlSessionFactory对象

SqlSessionFactory factory = builder.build(in);

//4.调用factory对象的openSession()方法,获取SqlSession对象

SqlSession sqlSession = factory.openSession();

//5.调用接口的方法

Integer count = sqlSession.getMapper(PersonMapper.class).findCount();

//6.输出对应的返回值count

System.out.println("count:" + count);

//7.关闭 SqlSession

sqlSession.close();

}

@Test

public void testInsert() throws Exception {

//1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息

InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

//2.实例化SqlSessionFactoryBuilder对象

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

//3.调用builder对象的builder()方法,获取SqlSessionFactory对象

SqlSessionFactory factory = builder.build(in);

//4.调用factory对象的openSession()方法,获取SqlSession对象

SqlSession sqlSession = factory.openSession();

//5.调用接口的方法

Person p = new Person();

p.setName("李四");

p.setNickname("一个人的夜晚上");

p.setAge(22);

sqlSession.getMapper(PersonMapper.class).addPerson(p);

//6.提交实物,该行代码必须放在关闭sqlsession之前

sqlSession.commit();

sqlSession.close();

}

@Test

public void testupdate() throws Exception {

//1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息

InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

//2.实例化SqlSessionFactoryBuilder对象

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

//3.调用builder对象的builder()方法,获取SqlSessionFactory对象

SqlSessionFactory factory = builder.build(in);

//4.调用factory对象的openSession()方法,获取SqlSession对象

SqlSession sqlSession = factory.openSession();

Person p2 = new Person();

p2.setId(2);

p2.setName("赵四");

p2.setNickname("来啊,造作啊");

p2.setAge(23);

sqlSession.getMapper(PersonMapper.class).updatePerson(p2);

//6.提交实物,该行代码必须放在关闭sqlsession之前

sqlSession.commit();

sqlSession.close();

}

@Test

public void testdel() throws Exception{

//1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息

InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

//2.实例化SqlSessionFactoryBuilder对象

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

//3.调用builder对象的builder()方法,获取SqlSessionFactory对象

SqlSessionFactory factory = builder.build(in);

//4.调用factory对象的openSession()方法,获取SqlSession对象

SqlSession sqlSession = factory.openSession();

sqlSession.getMapper(PersonMapper.class).delById(2);

sqlSession.commit();

sqlSession.close();

}

@Test

public void testdel2 () throws Exception{

//1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息

InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

//2.实例化SqlSessionFactoryBuilder对象

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

//3.调用builder对象的builder()方法,获取SqlSessionFactory对象

SqlSessionFactory factory = builder.build(in);

//4.调用factory对象的openSession()方法,获取SqlSession对象

SqlSession sqlSession = factory.openSession();

Person person = new Person();

person.setId(2);

sqlSession.getMapper(PersonMapper.class).delById2(person);

sqlSession.commit();

sqlSession.close();

}

@Test

public void testfindById () throws Exception{

//1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息

InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

//2.实例化SqlSessionFactoryBuilder对象

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

//3.调用builder对象的builder()方法,获取SqlSessionFactory对象

SqlSessionFactory factory = builder.build(in);

//4.调用factory对象的openSession()方法,获取SqlSession对象

SqlSession sqlSession = factory.openSession();

Person person = sqlSession.getMapper(PersonMapper.class).findById(1);

System.out.println("id"+ person.getId()+"name"+ person.getName()+"nickname"+ person.getNickname()+"age"+ person.getAge());

sqlSession.close();

}

@Test

public void testfindAll () throws IOException{

String str ="mybatis-config.xml";

InputStream in =Resources.getResourceAsStream(str);

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

SqlSessionFactory factory = builder.build(in);

SqlSession sqlSession = factory.openSession();

List all = sqlSession.getMapper(PersonMapper.class).findAll();

for(Person p:all){

System.out.println(p);

}

sqlSession.close();

}

@Test

public void testfindByName () throws IOException{

String str ="mybatis-config.xml";

InputStream in =Resources.getResourceAsStream(str);

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

SqlSessionFactory factory = builder.build(in);

SqlSession sqlSession = factory.openSession();

List list = sqlSession.getMapper(PersonMapper.class).findByName("wqz");

for(Person p:list){

System.out.println(p);

}

sqlSession.close();

}

@Test

public void testfindByPerson () throws IOException{

String str ="mybatis-config.xml";

InputStream in =Resources.getResourceAsStream(str);

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

SqlSessionFactory factory = builder.build(in);

SqlSession sqlSession = factory.openSession();

Person person = new Person();

List list = sqlSession.getMapper(PersonMapper.class).findByPerson(person);

for(Person p:list){

System.out.println(p);

}

sqlSession.close();

}

@Test

public void findByPerson2 () throws Exception {

//1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息

InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

//2.实例化SqlSessionFactoryBuilder对象

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

//3.调用builder对象的builder()方法,获取SqlSessionFactory对象

SqlSessionFactory factory = builder.build(in);

//4.调用factory对象的openSession()方法,获取SqlSession对象

SqlSession sqlSession = factory.openSession();

String name = "王五";

String nickname = "123";

List list = sqlSession.getMapper(PersonMapper.class).findByPerson2(name,nickname);

for(Person p:list){

System.out.println("name:"+p.getName()+"nickname"+p.getNickname());

}

sqlSession.close();

}

@Test

public void testfindCount(){

SqlSession sqlSession = MytabisUtil.getSqlSession();

Integer count = sqlSession.getMapper(PersonMapper.class).findCount();

System.out.println(count);

}

@Test

public void findColList(){

SqlSession sqlSession = MytabisUtil.getSqlSession();

List colList = sqlSession.getMapper(PersonMapper.class).findColList("Id");

for (Person p:colList){

System.out.println(p);

}

}

}pom.xml

代码语言:javascript代码运行次数:0运行复制

4.0.0

war

20211125

org.example

20211125

1.0-SNAPSHOT

org.mortbay.jetty

maven-jetty-plugin

6.1.7

8888

30000

${

project.build.directory}/${

pom.artifactId}-${

pom.version}

/

org.mybatis

mybatis

3.5.1

mysql

mysql-connector-java

5.1.36

junit

junit

4.12

test

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/157984.html原文链接:https://javaforall.cn