首页 > 编程语言 >小治同学的JAVAWEB学习笔记-Junit&反射&注解

小治同学的JAVAWEB学习笔记-Junit&反射&注解

时间:2023-06-08 16:33:33浏览次数:45  
标签:lang java String Junit Person 小治 注解 public JAVAWEB


Junit 单元测试

Junit使用:白盒测试 步骤 1.定义一个测试类(测试用类) 建议: 测试类名:北侧是的类+Test 包名:XXX.XXX.XX.Test 2.定义测试方法:可以独立运行 建议: 方法名:test测试的方法名 返回值 void 参数列表 空参 3.给方法加@Test 判定结果 1.红色代表失败 2.绿色代表成功在这里 原代码

public class Caltest {
    public static void main(String[] args) {
        Cal c = new Cal();
        int ans = c.add(1,2);
        System.out.println(ans);
    }
}

需要引入Junit依赖项, 可以直接在测试代码写入@Test来声明,这是测试代码,并由系统添加依赖路径 测试代码 使用断言操作Assert.assertEquals(期望值,目标值); 来进行判断输出值是否与期望一致

package itcast.junit.Test;

import itcast.junit.Cal;
import org.junit.Assert;
import org.junit.Test;

public class CalTest {
    @Test
    public void testAdd(){
        System.out.println("我被执行了");
        Cal c =  new Cal();
        int result = c.add(1,2);
        Assert.assertEquals(3,result);
    }
}

失败状态

小治同学的JAVAWEB学习笔记-Junit&反射&注解_反射


测试通过状态

小治同学的JAVAWEB学习笔记-Junit&反射&注解_Junit_02

补充
@Before
修饰的方法会在测试方法之前被自动执行
@After
修饰的方法会在测试方法之后被自动执行

反射:框架设计的灵魂

框架:半成品软件。可以在狂剑的基础上进行软件开发,简化编码反射:将类的各个组成部分封装为其他对象,这就是反射机制 好处: 1.可以在程序运行工程中操作这些对象 2.可以解耦,提高程序的可扩展性 java代码在计算机中经历的三个阶段: 1.Source源代码阶段 字节码文件 Person.java->(javac编译)->Person.class 2.ClassLoader类加载器 成员变量Field[] fields 构造方法Constructor[] Con 成员方法Method[] methods 3.RunTime

小治同学的JAVAWEB学习笔记-Junit&反射&注解_测试_03


定义了一个字符串,把字符串文件加载进了内存,

在内存中有一个Class对象,把所有方法都放到Method[]数组中

使用的时候只需要把Method[]所有方法拿出来即可

这就是一个反射的机制

相当于IDEA持续运行自动编译

小治同学的JAVAWEB学习笔记-Junit&反射&注解_java_04

1.Class.forname(”全类名“)将字节码文件加载进内存,返回Class对象2.类名.Class通过类名的属性Class获取 3.对象.getClass():getClass()方法在Objdect类中定义着 对象: 同一个字节码文件(*.class) *多用于配置文件,将类名定义在配置文件中 读取文件,加载类 在一次程序运行过程中,只会被加载一次 *多用于参数的传递 不论通过哪一种方式获取的Class对象都是同一个 *多用于多项的获取字节码方式

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试获取对象

public class ReflectDemo1 {
    public static void main(String[] args) throws Exception{
        Class cls1 =  Class.forName("testpackage.domian.Person");
        System.out.println(cls1);

        Class cls2 = Person.class;
        System.out.println(cls2);

        Person p  = new Person();
        Class cls3 = p.getClass();
        System.out.println(cls3);

        System.out.println(cls1==cls2&&cls1==cls3);
    }
}

输出

class testpackage.domian.Person
class testpackage.domian.Person
class testpackage.domian.Person
true

Filed getFields(String name) 获取指定名字的成员变量 Filed[] getDeclaredFields() 获取所有成员本良不考虑修饰符 Filed getDeclaredField(String name) 2.获取构造方法们 Constructor<?>[] getConstructors() Constructor<T> getConstructors(类<?>... parameterTypes) Constructor<T> getDeclaredConstructors(类<?>... parameterTypes) Constructor<?>[] getDeclaredConstructors() 3.获取成员方法们 Method[] getMethods() Method getMethods(String name,类<?>...parameterTypes) Method[] getDeclaeredMethods() Method getDeclaeredMethods(String name,类<?>...parameterTypes) 4.获取类名 String getName() Field:成员变量 操作: 1.设置值 set(Object obj,Object value) 2.获取值 get(Object obj) 3.setAccessible(true)忽略安全检查,称为暴力反射

Class对象,获取成员变量的方法
public static void main(String[] args) throws Exception{
        Class personClass = Person.class;

        //Filed[] getFields()
        //获取所有public修饰的成员变量
        Field[] fields = personClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        System.out.println("------------");
        //Filed[] getDeclaredFields(String name)
        //获取成员变量a的值
        Field a = personClass.getField("a");
        Person p = new Person();//生成一个对象
        Object value = a.get(p);
        System.out.println(value);
        a.set(p,"小春");
        System.out.println(p);

        System.out.println("----------------------------");
        //Filed[] getDeclaredFields() 或许所有的成员变量,不用考虑修饰符
        Field[] declaredFields = personClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }

        System.out.println("------------------------");
        //Filed[] getDeclaredFields(String name)
        //访问私有时候,忽略访问权限修饰符的安全检查
        Field b = personClass.getDeclaredField("b");
        b.setAccessible(true);//暴力反射
        Object value2 = b.get(p);
        System.out.println(value2);
    }

输出

public java.lang.String testpackage.domian.Person.a
------------
null
Person{name='null', age=0, a='小春', b='null'}
----------------------------
private java.lang.String testpackage.domian.Person.name
private int testpackage.domian.Person.age
public java.lang.String testpackage.domian.Person.a
private java.lang.String testpackage.domian.Person.b
------------------------
null

Constructor:构造方法
创建对象
T newInstance(Object… initargs)

如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法
public class ReflectDemo3 {
    /*
    	2.获取构造方法们
		Constructor<?>[] getConstructors()
		Constructor<T> getConstructors(类<?>... parameterTypes)

		Constructor<T> getDeclaredConstructors(类<?>... parameterTypes)
		Constructor<?>[] getDeclaredConstructors()
    * */

    public static void main(String[] args) throws Exception{
        Class personClass = Person.class;
        Constructor constructor = personClass.getConstructor(String.class, int.class);
        System.out.println(constructor);
        
        //创建对象
        Object person = constructor.newInstance("小春", 21);
        System.out.println(person);
        System.out.println("-------------------");

        Constructor constructor1 = personClass.getConstructor();
        Object person1 = constructor1.newInstance();
        System.out.println(person1);

        System.out.println("-------------------");

        Object o = personClass.newInstance();
        System.out.println(o);
    }
}

输出

public testpackage.domian.Person(java.lang.String,int)
Person{name='小春', age=21, a='null', b='null'}
-------------------
Person{name='null', age=0, a='null', b='null'}
-------------------
Person{name='null', age=0, a='null', b='null'}

获取成员方法们的范例

Method:方法对象
执行方法:
Object invoke(Object obj,Object… args)
获取方法名称:
String getName:()

package testpackage.domian;

public class Person {
    private String name;
    private int age;
    public String a;
    private String b;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat(){
        System.out.println("eat...");
    }

    public void eat(String food){
        System.out.println("eat..."+food);
    }

    public Person() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", a='" + a + '\'' +
                ", b='" + b + '\'' +
                '}';
    }
}

主要

public class ReflectDemo3 {
    /*
    	3.获取成员方法们
		Method[] getMethods()
		Method getMethods(String name,类<?>...parameterTypes)

		Method[] getDeclaeredMethods()
		Method getDeclaeredMethods(String name,类<?>...parameterTypes)
    * */

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class personClass = Person.class;
        Method eat_method = personClass.getMethod("eat");
        Person p = new Person();
        //执行方法
        eat_method.invoke(p);

        Method eat_method2 = personClass.getMethod("eat",String.class);
        eat_method2.invoke(p,"饭");

        System.out.println("------------");
        //获取所有Public修饰的方法
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
            //获取类名
            System.out.println(method.getName());
        }
    }
}

输出

eat...
eat...饭
------------
public java.lang.String testpackage.domian.Person.toString()
toString
public java.lang.String testpackage.domian.Person.getName()
getName
public void testpackage.domian.Person.setName(java.lang.String)
setName
public void testpackage.domian.Person.setAge(int)
setAge
public int testpackage.domian.Person.getAge()
getAge
public void testpackage.domian.Person.eat()
eat
public void testpackage.domian.Person.eat(java.lang.String)
eat
public final void java.lang.Object.wait() throws java.lang.InterruptedException
wait
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
wait
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
wait
public boolean java.lang.Object.equals(java.lang.Object)
equals
public native int java.lang.Object.hashCode()
hashCode
public final native java.lang.Class java.lang.Object.getClass()
getClass
public final native void java.lang.Object.notify()
notify
public final native void java.lang.Object.notifyAll()
notifyAll

案例:
需求:写一个框架,可以帮我们创建任意类的对象,并且执行其中的方法
实现:
1.配置文件
2.反射

步骤:
	1.将需要创建的对象的全类名和需要执行的方法定义在配置文件
	2.在程序加载读取配置文件
	3.使用反射技术加载类文件进内存
	4.创建对象
	5.执行方法

我创建了testpackage.domian.Person这个类
定义了eat这个方法
配置文件

className = testpackage.domian.Person
methodName = eat

public class ReflectTest {
    public static void main(String[] args) throws Exception {
        //可以创建任意对象,执行任意方法
        //加载配置文件
        //1.1创建对象
        Properties pro = new Properties();
        //1.2加载配置文件,转换为一个集合
        //1.2.1获取Class目录下的配置文件
        //pro.load();
        ClassLoader classLoader = ReflectTest.class.getClassLoader();//类加载器
        InputStream is = classLoader.getResourceAsStream("pro.properties");//获取文件字节流
        pro.load(is);

        //2.获取配置文件中的定义的数据
        String classNmae = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");

       // 3.加载该类进内存
       Class cls = Class.forName(classNmae);

       //4.创建对象
        Object obj = cls.newInstance();

        //5.获取方法对象
        Method method = cls.getMethod(methodName);

        //6.执行方法
        method.invoke(obj);
    }
}

输出

eat...

注解

注释:用文字描述给程序员看的注解:注解(Annotation),也叫元数据。一种代码级别的说明。 它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。 它可以声明在包、类、字段、方法、局部变量、 方法参数等的前面,用来对这些元素进行说明,注释。

作用分类:

①编写文档:通过代码里标识的注解生成文档【生成文档doc文档】

package itcast.junit.Test;

/*
@since 1.5
@author bi
@version 1.5
* */
public class AnnoDemo1 {
 /*
    @param a 整数
    @param b 整数
    @return 两数之和
 * */
  public int add(int a,int b){
      return a+b;
  }
}

使用javadoc进行编译

使用ANSI编码

小治同学的JAVAWEB学习笔记-Junit&反射&注解_测试_05

小治同学的JAVAWEB学习笔记-Junit&反射&注解_Junit_06


② 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】

③编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】

JDK中预定义的一些注解

@Override	:检测被该注解标注的方法是否是继承自父类(接口)的
@Depprecated:该注解标注的内容,表示已过时
@SuperessWarnings:压制警告
@SuppressWarnings("all")//压制类中所有警告
public class AnnoDemo2 {
    @Override
    public String toString() {
        return super.toString();
    }
    
    @Deprecated//过时注释
    public void show(){
        //有缺陷
    }
    
    public  void showMore(){
            //替代SHOW1方法
    }
    
    
}

自定义注解

自定义注解格式: 元注解 public @interface 注解名称{} 本质:注解本质上就是一个接口,该接口继承Annotation接口 ```java public interface itcast.junit.Test.AnnoDemo3 extends java.lang.annotation.Annotation { } ``` 属性:接口中的抽象方法 要求: 1.属性的返回值类型 基本数据类型 String 枚举 注解 2.定义了之后需要赋值 1.如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值 2.如果只有一个属性需要赋值,并且属性名字为value,则value可以省略,直接定义值即可 3.数组赋值时,值用{}包括。如果数组中只有一个值,则{}省略

元注解:

注解

public @interface AnnoDemo3 {
    int show();
    boolean flag();
    /*
    String show2();
    String[] per();
    */
}

主要

@AnnoDemo3(show = 1,flag = true)//赋值
public class AnnoDemo4 {
}

属性:接口中的抽象方法 1.属性的返回值类型 基本数据类型 String 枚举 注解 以上类型的数组 2.定义了属性,在使用时需要给属性赋值 1.如果定义属性时,使用Default关键字给属性默认初始化,则使用注解时,可以不进行属性的赋值 2.如果只有一个属性需要复制,且属性的名称是Value,则value可以省略,直接定义值即可 3.数组赋值时,值使用{}包裹,如果数组中只有一个值,则{}省略 元注解:描述注解的注解 @Target:描述注解能够作用的位置 TYPE:作用于类上 METHOD:可以作用于方法上 FIELD:可以作用于成员变量上

注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
public @interface AnnoDemo5 {

}

测试

@AnnoDemo5
public class Worker {
    @AnnoDemo5
    public  String name ="testname";
    
    @AnnoDemo5
    public void show(){
        
    }
}
@Retention:描述注解被保留的阶段
	@Retention(RetentionPolicy.RUNTIME):
		当前被描述的注解,会保留到Class字节码文件中,并被JVM读取到
@Documented:描述直接是否抽取到API文档中

import java.lang.annotation.*;

@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
@Documented
public @interface AnnoDemo5 {

}

@AnnoDemo5
public class Worker {
    @AnnoDemo5
    public  String name ="testname";

    @AnnoDemo5
    public void show(){

    }
}

javadoc

小治同学的JAVAWEB学习笔记-Junit&反射&注解_注解_07


小治同学的JAVAWEB学习笔记-Junit&反射&注解_测试_08

@Inherited:描述注解是否被子类继承
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
@Documented
@Inherited
public @interface AnnoDemo5 {

}

子类

public class Teacher extends  Worker{

}

在程序使用(解析)注解:获取注解中定义的属性值

接口可以存放的方法:

public abstract String show();

1.获取注解定义的位置的对象:(Class,Method,Field)
2.获取指定的注解
getAnnotation(Class)

//其实就是在内存中生成了一个该注解接口的子类实现对象
            /*
        public class ProImp1 implements Pro{
            public String className(){
                return "itcast.junit.Test.Demo1"';
            }
            public String methodName(){
                return "show"';
            }
        }
    * */

3.调用注解中的抽象方法获取配置的属性值

注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Pro {
    /*
    描述需要执行的类名和方法名
    * */

    String className();
    String methodName();


    /*
        public class ProImp1 implements Pro{
            public String className(){
                return "itcast.junit.Test.Demo1"';
            }
            public String methodName(){
                return "show"';
            }
        }
    * */
}

正常使用

@Pro(className = "itcast.junit.Test.Demo1",methodName = "show")
public class ReflectTest {
    public static void main(String[] args) throws Exception {
        //可以创建任意对象,执行任意方法


        //1.解析注解
        //1.1就获取该类的字节码文件对象
        Class<ReflectTest> reflectTestClass = ReflectTest.class;

        //2.获取上边的注解对象
        //其实就是在内存中生成了一个该注解接口的子类实现对象
            /*
        public class ProImp1 implements Pro{
            public String className(){
                return "itcast.junit.Test.Demo1"';
            }
            public String methodName(){
                return "show"';
            }
        }
    * */
        Pro an = reflectTestClass.getAnnotation(Pro.class);

        //3.调用注解对象中定义的抽象方法,获取返回值
        String ClassName = an.className();
        String methodName = an.methodName();
        System.out.println(ClassName+"      "+methodName);

        // 3.加载该类进内存
        Class cls = Class.forName(ClassName);

        //4.创建对象
        Object obj = cls.newInstance();

        //5.获取方法对象
        Method method = cls.getMethod(methodName);

        //6.执行方法
        method.invoke(obj);
    }
}

输出

itcast.junit.Test.Demo1      show
demo1...show..

测试框架

小结:
1.以后大多时候,我们会使用注解,而不是自定义注解
2.注解给谁用?
1.编辑器
2.解析程序
3.注解不是程序的一部分,可以理解为注解就是一个标签

定义类

public class Calculator {
    @Check
    public void add(){
        System.out.println("1 + 0"+(1+0));
    }
    @Check
    public void sub(){
        System.out.println("1 - 0"+(1-0));
    }
    @Check
    public void mul(){
        System.out.println("1 * 0"+(1*0));
    }
    @Check
    public void div(){
        System.out.println("1 / 0"+(1/0));
    }
    public void show(){
        System.out.println("没有BUG");
    }
}

注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Check {
}

主要

/*
    简单的测试框架
    当主方法执行后,会自动自行被检测的所有方法(加了注解),判断是否有异常,然后记录到文件中
* */
public class TestCheck {
    public static void main(String[] args) throws IOException {
        //创建对象
        Calculator c = new Calculator();

        //获取字节码文件对象
        Class cls = c.getClass();

        //出现异常的次数
        int number = 0;
        BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
        //获取所有方法
        java.lang.reflect.Method[] methods = cls.getMethods();
        for (Method method : methods) {
            if(method.isAnnotationPresent(Check.class)){
                try {
                    method.invoke(c);
                } catch (Exception e) {
                    number++;
                    bw.write(method.getName()+" 方法出异常了");
                    bw.newLine();
                    bw.write("异常的名称"+e.getCause().getClass().getSimpleName());
                    bw.newLine();
                    bw.write("异常的原因"+e.getCause().getMessage());
                    bw.newLine();
                    bw.write("-------------------------------------");
                    bw.newLine();
                }
            }
        }
        bw.write("本次测试一共出现"+number+"次异常");
        bw.flush();
        bw.close();
        //判断方法上石佛有相应注解

        //有,执行

        //捕获异常

    }
}

输出

1 + 01
1 * 00
1 - 01

bug.txt

div 方法出异常了
异常的名称ArithmeticException
异常的原因/ by zero
-------------------------------------
本次测试一共出现1次异常


标签:lang,java,String,Junit,Person,小治,注解,public,JAVAWEB
From: https://blog.51cto.com/u_16014765/6441282

相关文章

  • JavaWeb基础(5)—— 浅析 Servlet 与 JSP 两者之间的区别
    维基百科中JSP的定义JSP(全称JavaServerPages)是一种使软件开发者可以响应客户端请求,而动态生成HTML、XML或其他格式文档的Web网页的技术标准。JSP技术是以Java语言作为脚本语言的,JSP网页为整个服务器端的Java库单元提供了一个接口来服务于HTTP的应用程序。JSP使Java代码和特定的......
  • Druid使用起步—在javaWeb项目中配置监控
    配置druid监控springjdbc代码[url]http://19950603.blog.51cto.com/9921553/1616566[/url]AliDruid连接池与监控配置[url]http://langmnm.iteye.com/blog/2112099[/url]阿里巴巴Druid配置监控官方:[url]https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatV......
  • javaweb课程设计——商城项目
    目录本项目前端成员csdn地址:一、项目截图二、前端项目介绍最后源码地址本项目前端成员csdn地址:【后端】【前端】一、项目截图二、前端项目介绍ChangeAtWill:前台项目ChangeAtWill-admin:后台项目前端需要环境nodejsv16版本下载链接https://nodejs.org/download/release/v16......
  • IDEA 创建JavaWeb项目(不依赖 springboot)手动整合 SSM框架
    目录 1.创建一个Maven项目2.创建webapp和WEB-INF目录即可3.设置web.xml文件和web文件目录4.导入相关ssm框架的pom依赖文件5.创建对应的包结构:6.添加配置文件(配置mybatis、spring、springMvc等配置文件)7.web.xml配置文件8. 配置本地Tomcat运行9.打包发布1.创建一个Mav......
  • JavaWeb——Tomcat服务器的安装与使用
    今天阿Q带大家了解服务器的概念以及tomcat服务器的安装和使用方法,废话不多说直接上干货。Web开发中的常见概念(1)B/S系统和C/S系统Brower/Server:浏览器、服务器系统-----网站Client/Server:客户端、服务器系统-----QQ、大型游戏(2)web应用服务器供向外部发布web资源的服务器软件......
  • JavaWeb
    JavaWeb1、基本概念1.1、前言web开发:web,网页的意思静态webhtml,css提供给所有人看的数据始终不会发生变化动态web几乎所有的网站都是动态的提供给所有人看的数据始终会发生变化,每个人在不同的时间,不同的地点看到的信息各不相同技术栈:Servlet/JSP,ASP,PHP在Java中......
  • Javaweb中在SQL语句中使用未知数进行多表查询
    这个问题主要是匹配好引号和单引号即可。如果是varchar型,那么变量要带单引号('),如果是int型就不用带。同时要注意用+号进行String的拼接。示例:publicList<Student>huizong_bujige(Stringkemu1){List<Student>list=newArrayList<>();Connectionconn......
  • JavaWeb 解决乱码问题
    自写过滤器解决文件结构代码配置EncondingFilerpackagefilter;importjavax.servlet.*;importjava.io.IOException;publicclassEncondingFilterimplementsFilter{@Overridepublicvoidinit(FilterConfigfilterConfig)throwsServletException{......
  • javaWeb中的编码解码
    在上篇博客中LZ介绍了前面两种场景(IO、内存)中的Java编码解码操作,其实在这两种场景中我们只需要在编码解码过程中设置正确的编码解码方式一般而言是不会出现乱码的。对于我们从事java开发的人而言,其实最容易也是产生乱码最多的地方就是web部分。首先我们来看在javaWeb中有哪些地方存......
  • 【JavaWeb-02】Web服务器
    文章目录2.web服务器2.1技术讲解2.2web服务器2.web服务器2.1技术讲解JSP/Servlet:B/S:浏览和服务器C/S:客户端和服务端sun公司主推的B/S架构基于Java语言的(所有的大公司,或者一些开源的组件,都是用Java写的)可以承载三高问题带来的影响2.2web服务器IIS:微软的Tmocat:Java初学人员......