概述:
B/S 架构的全称为 Browser/Server,即浏览器/服务器结构。 Browser 指的是 Web 浏览器,极少数业务逻辑在前端实现,主要的业务逻辑在服务器端现,
Browser 客户端,WebApp 服务器端和 DB 端构成所谓的三层架构。 B/S 架构的系统无须特别安装,只有 Web 浏览器即可。B/S 架构中,显示逻辑交给了
Web浏览器,业务处理逻辑放在了 WebApp 上,这样就避免了庞大的胖客户端,减少了客户端的压力。因为客户端包含的逻辑很少,因此也被成为瘦客户端。
优点:
( 1) 客户端无需安装,有 Web 浏览器即可。
( 2) BS 架构可以直接放在广域网上,通过一定的权限控制实现多客户访
问的目的,交互性较强。
( 3) BS 架构无需升级多个客户端,升级服务器即可。
缺点:
( 1) 在跨浏览器上, BS 架构不尽如人意。
( 2) 表现要达到 CS 架构的程度需要花费不少精力。
( 3) 在速度和安全性上需要花费巨大的设计成本,这是 BS 架构的最大问题。
B/S架构图:
B/S 架构的系统参与者:
第一: Web 客户端 Browser
第二: Web 服务器 Server
第三: WebApp
第四:数据库服务器
B/S 架构的系统中参与者之间的接口与协议:
第一: Web 客户端 Browser 和 Web 服务器端 Server 之间是 W3C 制定的 HTTP 协议。
第二: Web 服务器和 Web 应用之间是 SUN 制定的 Servlet 接口。
第三: Web 应用中的小 java 程序和数据库服务器之间是 SUN 制定的 JDBC 接口。
B/S架构:多线程访问服务器
BootStrap:
package com.bjpowernode.core; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; import com.bjpowernode.util.Logger; /** * 程序主入口 * @author * @version 1.0 * @since 1.0 */ public class BootStrap { public static void main(String[] args) { //程序入口 start(); } private static void start() { /** * 程序启动入口 */ Logger.log("httpserver start"); ServerSocket serverSocket = null; Socket clientSocket = null; BufferedReader br = null; try { //记录开启时间 long start = System.currentTimeMillis(); //从server.xml配置文件中获取端口号:8080 int port = ServerParser.getPort(); Logger.log("httpserver-port:" + port); //创建服务端套接字,并且绑定端口号:8080 serverSocket = new ServerSocket(port); //记录结束时间 long end = System.currentTimeMillis(); Logger.log("httpserver started:" + (end - start) + "ms"); while(true){ //开始监听网络,此时程序处于等待状态,等待接收 clientSocket = serverSocket.accept(); new Thread(new HandlerRequest(clientSocket)).start(); } //接受客户端消息 /*br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); //打印消息 String temp = null; while((temp = br.readLine()) != null){ System.out.println(temp); }*/ } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ //关闭资源 if(br != null){ try { br.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(clientSocket != null){ try { clientSocket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(serverSocket != null){ try { serverSocket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
DateUtil:
package com.bjpowernode.util; import java.text.SimpleDateFormat; import java.util.Date; /** * 日期处理类 * @author * @version 1.0 * @since 1.0 * */ public class DateUtil { private DateUtil(){ } /** * 获取系统当前时间 * @return Strinng [yyyy-MM-dd HH:mm:ss SSS] */ public static String getNowTime(){ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); Date nowTime = new Date(); return dateFormat.format(nowTime); } }
Logger:
package com.bjpowernode.util; import java.text.SimpleDateFormat; import java.util.Date; /** * 记录日志 * @author * @version 1.0 * @since 1.0 */ public class Logger { //工具类的方法往往都是静态的,直接通过类名调用即可,不需要创建对象 //工具类的构造方法往往是私有的,但不是必须的 private Logger(){ } /** * 记录普通日志 * @param info */ public static void log(String info){ /*SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); //获取系统当前时间 Date nowTime = new Date(); String strTime = dateFormat.format(nowTime);*/ System.out.println("[INFO]" + DateUtil.getNowTime() + "" + info); } }
LoggerTest:
package com.bjpowernode.util; import java.text.SimpleDateFormat; import java.util.Date; /** * 记录日志 * @author * @version 1.0 * @since 1.0 */ public class Logger { //工具类的方法往往都是静态的,直接通过类名调用即可,不需要创建对象 //工具类的构造方法往往是私有的,但不是必须的 private Logger(){ } /** * 记录普通日志 * @param info */ public static void log(String info){ /*SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); //获取系统当前时间 Date nowTime = new Date(); String strTime = dateFormat.format(nowTime);*/ System.out.println("[INFO]" + DateUtil.getNowTime() + "" + info); } }
package com.bjpowernode.core; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; import com.bjpowernode.util.Logger; public class HandlerRequest implements Runnable { private Socket clientSocket; public HandlerRequest(Socket clientSocket) { this.clientSocket = clientSocket; } @Override public void run() { // 负责处理客户端发送的请求 BufferedReader br = null; Logger.log("httpserver 线程Thread-Name:" + Thread.currentThread().getName()); try { // 接受消息 br = new BufferedReader(new InputStreamReader( clientSocket.getInputStream())); // 打印消息 String temp = null; while ((temp = br.readLine()) != null) { System.out.println(temp); } } catch (Exception e) { e.printStackTrace(); } finally{ //关闭资源 if(br != null){ try { br.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(clientSocket != null){ try { clientSocket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
package com.bjpowernode.core; import java.io.File; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.DocumentException; import org.dom4j.io.SAXReader; /** * 解析server.xml配置文件 * @author * @version 1.0 * @since 1.0 */ public class ServerParser { public static int getPort(){ //默认值 int port = 8080; try{ //创建解析器 SAXReader saxReader = new SAXReader(); //通过解析器的read方法将配置的文件读取到内存中去 Document document = saxReader.read(new File("conf/server.xml")); //获取connector节点元素对象的xpath路径:/server/service/connector //获取connector节点元素对象的xpath路径:server//connector //获取connector节点元素对象的xpath路径://connector Element connectorElt = (Element) document.selectSingleNode("//connector"); //获取port属性对象的值 port = Integer.parseInt(connectorElt.attributeValue("port")); } catch(Exception e){ e.printStackTrace(); } return port; } }
server.xml:
<?xml version="1.0" encoding="UTF-8"?> <server> <service> <connector port="8080"></connector> </service> </server>
所建工程:
运行结果: