JAVAEE Web简单开发

概述:

JavaEE Web开发是基于B/S(浏览器/服务器)架构实现的,客户端只需要浏览器,应用程序的逻辑和数据都存储在服务器端。浏览器只需要请求服务器,获取Web页面,并把Web页面展示给用户即可。Web开发通常是指开发服务器端的Web应用程序。

HTTP协议:

在Web应用中,浏览器请求一个URL,服务器就把生成的HTML网页发送给浏览器,而浏览器和服务器之间的传输协议是HTTP,而HTTP协议是一个基于TCP协议之上的应用层协议,基于请求-响应模式。HTTP Server实现流程:

代码实例:

// 基于TCP协议连接 + HTTP协议通信 的服务器端
public class HttpServer {
	public static void main(String[] args) {
		try (ServerSocket serverSocket = new ServerSocket(8080)) {
			
			while(true) {
				// 客户端基于HTTP协议发起请求
				Socket clientSocket = serverSocket.accept();
				System.out.println("有新的客户端连接:");
				
				// 读取到客户端的请求头内容(基于http协议格式)
				BufferedReader reader = 
						new BufferedReader(
								new InputStreamReader(clientSocket.getInputStream()));
				
				String line = null;
				while((line = reader.readLine()) != null) {
					// 读到空行,代表请求头结束
					// 由于是GET请求,不存在request body(请求体)
					// 所以退出请求头的读取
					if(line.isEmpty()) {
						break;
					}
					System.out.println(line);
				}
				
				System.out.println("开始响应.....");
				
				try(BufferedWriter out = new BufferedWriter(
						new OutputStreamWriter(
								clientSocket.getOutputStream()));){
					// 响应内容
					String response = "您优惠券是:<b>"+UUID.randomUUID().toString()+"</b>";
					
					// 按照HTTP协议将响应内容输出至客户端浏览器
					// response header 响应头
					out.write("HTTP/1.1 200 OK\r\n");
					out.write("Connection: close\r\n");
					out.write("Content-Type: text/html\r\n");
					out.write("Content-Length: " + response.length() + "\r\n");
					out.newLine(); // 换行
					out.newLine(); // 换行
					// reponse body 响应体
					out.write(response);
				}
				
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
}

Servlet:

在JavaEE平台上,处理TCP连接,解析HTTP协议这些底层工作统统扔给现成的Web服务器去做,开发人员只只需要使应用程序跑在Web服务器上。为了实现这一目的,JavaEE提供了Servlet API,我们使用Servlet API编写自己的Servlet来处理HTTP请求,Web服务器实现Servlet API接口,实现底层功能:

                 ┌───────────┐
                 │My Servlet │应用程序
                 ├───────────┤
                 │Servlet API│servlet接口
┌───────┐  HTTP  ├───────────┤
│Browser│<──────>│Web Server │web服务器
└───────┘        └───────────┘
客户端   请求/响应

代码实例:

// WebServlet注解表示这是一个Servlet,并映射到地址 hello.do
@WebServlet(urlPatterns = "/hello.do")
public class HelloServlet extends HttpServlet {
    protected void doGet(HttpServletRequest req//请求, HttpServletResponse resp//响应)
            throws ServletException, IOException {
        // 设置响应类型:
        resp.setContentType("text/html");
        // 获取输出流:
        PrintWriter pw = resp.getWriter();
        // 写入响应:
        pw.write("<h1>Hello, world!</h1>");
        // 最后不要忘记flush强制输出:
        pw.flush();
    }
}

Servlet生命周期:

通过一个URL路径发起对一个Servlet请求的过程中,其本质是在调用执行Servlet实例的doXXX()方法。该Servlet实例创建和使用的过程,被称为Servlet的生命周期。

整个生命周期包括:实例化、初始化、服务、销毁

代码实例:


@WebServlet("/demo")
public class demoServlet extends HttpServlet {
    //实例化:根据Servlet请求的路径(PS:demo),查找该Servlet的实例
    //若实例不存在,调用构造方法,完成Servlet实例的创建。
    public demoServlet(){
        System.out.println("实例化:demo实例被创建");
    }
    //初始化:通过该Servlet的实例,调用init()方法,执行初始化的逻辑
    @Override
    public void init() throws ServletException {
        System.out.println("初始化:demo实例初始化");
    }
    //服务:通过该Servlet的实例,调用service()方法,根据请求方式,调用方法
    //如果子类没有重写该方法,则调用HttpServlet父类的service()方法,在父类的该方法中进行请求方式的判断
    //如果子类重写doXXX()方法,则调用子类重写后的doXXX()方法;
    //如果子类没有重写doXXX()方法,则调用父类的doXXX()方法,在父类的方法实现中,返回一个405状态码:请求的方式服务器不提供支持
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("请求首页数据");
    }
    //销毁:服务器关闭或重启时,会销毁所有的Servlet实例,会调用Servlet实例的destroy()方法
    @Override
    public void destroy() {
        System.out.println("销毁:demo实例被销毁");
    }
}

Session与Cookie:

因为HTTP协议是一个无状态协议,因此当一个用户访问多个页面时,服务器无法识别两个请求是否为同一用户发出,为了追踪用户状态,Session与Cookie两种会话方式应运而生。

Session:

Session是一种基于唯一ID识别用户身份的机制,第一次访问服务器后,会自动获得一个Session ID。如果用户在一段时间内没有访问服务器,那么Session会自动失效,下次即使带着上次分配的Session ID访问,服务器也认为这是一个新用户,会分配新的Session ID。
JavaEE的Servlet机制内建了对Session的支持。当我们需要获取Session时,可以通过request请求对象的getSession()方法。例如;

HttpSession session = request.getSession();

服务端对session以map形式管理,通过getSession(true)方法创建一个32位随机字符JSESSIONID作为key放在map列表中,value是HttpSession对象;JSESSIONID作为key放在cookie里面,JSESSIONID 的值HttpSession作为value发送给客户端,客户端保存session信息,下次请求服务器时会携带JSESSIONID值,服务端拿到JESSIONID的值会去session列表查找对应的value

keyvalue
JSESSIONID1HttpSession1
JSESSIONID2HttpSession2

Cookie:

Cookie是由服务器产生,存放在客户端的一系列键值对组成的文本信息,大小最多只有4K。Session中的JSESSIONID便是一个特殊的,由服务器生成的cookie,不同浏览器之间不能共享cookie。我们可以在客户端自己指定生成cookie。

读取Cookie:

private String parseLanguageFromCookie(HttpServletRequest req) {
    // 获取请求附带的所有Cookie:
    Cookie[] cookies = req.getCookies();
    // 如果获取到Cookie:
    if (cookies != null) {
        // 循环每个Cookie:
        for (Cookie cookie : cookies) {
            // 如果Cookie名称为lang:
            if (cookie.getName().equals("lang")) {
                // 返回Cookie的值:
                return cookie.getValue();
            }
        }
    }
    // 返回默认值:
    return "en";
}

创建Cookie:

@WebServlet("/setCookie")
public class CookieServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie cookie = new Cookie("user_name","GGBond");//指定cookie的key
        Cookie cookie1 = new Cookie("pass_word","123456");//指定cookie的value
        //调用addCookie方法添加
        resp.addCookie(cookie);
        resp.addCookie(cookie1);
        //重定向至web.html页面
        resp.sendRedirect("web.html");
    }
}

Session与Cookie对比

属性SessionCookie
产生时间首次请求时产生首次响应时由服务器产生发送回客户端
保存地址保存在服务端保存在客户端
过期时间

由服务端决定,客户端/服务端关闭即消逝

在cookie生成的时候设置,可永久保存
安全性Session > Cookie
作用跟踪客户端浏会话,Cookie可保存用户账户密码及用户特征

综合案例:

//匿名聊天室
@WebServlet("/ChatServlet")
public class ChatServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //处理报文乱码
        req.setCharacterEncoding("UTF-8");

        //获得聊天记录
        String IP = req.getRemoteAddr();//获得IP
        String user = req.getParameter("user");
        String content = req.getParameter("content");//获取发言内容,与客户端input name需要一致

        //统计发言次数
        HttpSession session = req.getSession();//创建session对象
        Integer chatcount = (Integer)session.getAttribute("chat_count");//通过key获得发言次数
        if (chatcount == null){
            chatcount = 1;
            session.setAttribute("chat-count",chatcount);//将发言次数chatcount保存在session中,key为chat-count
        }
        //通过判断发言次数赋予不同的头衔
        String face = "";
        if (chatcount >= 5){
            face = "<img src='pic/face1.png'/>";
        }else if (chatcount >= 3){
            face = "<img src='pic/face2.png'/>";
        }else if (chatcount >=1){
            face = "<img src='pic/face3.png'/>";
        }

        String chatMsg = String.format("%s%s说:%s[%s]",face,user,content, LocalTime.now());//输出

        //使用Cookie统计个人发言次数
        Cookie[] cookies = req.getCookies();//获取Cookie对象
        int total = 1;
        if (cookies != null){
            //查找指定Cookis
            Cookie cookie = null;
            //遍历并匹配
            for (Cookie ck: cookies){
                if (ck.getName().equals("total")){
                    cookie = ck;
                    total = Integer.parseInt(ck.getValue());
                }
            }
            if (cookie == null){
                cookie = new Cookie("total",String.valueOf(total));
            }else {
                cookie = new Cookie("total",String.valueOf(total+1));
            }
        }

        //存储聊天记录
        ServletContext application = req.getServletContext();

        //获得application范围内的聊天记录
        List<String> messageList = (List<String>)application.getAttribute("chat_message_list");//通过key获取聊天记录
        //无记录时创建存储集合
        if (messageList == null){
            messageList = new ArrayList<String>();
            application.setAttribute("chat_message_list",messageList);//将聊天记录messageList保存在session中,key为chat_message_list
        }
        //向集合添加聊天记录
        messageList.add(chatMsg);

        //显示聊天记录
        resp.setContentType("text/html;charset=utf-8");//设置文本参数
        PrintWriter out = resp.getWriter();//getWriter获取输入流,返回一个PrintWriter object
        for (String messige: messageList) {
            out.write(messige+"<br/>");//PrintWriter可以直接调用write()或print()方法,把字符串作为参数写入
        }
        out.flush();//PrintWriter可以直接调用write()或print()方法,把字符串作为参数写入
    }

}

浏览器端页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>焦灼の聊天室</title>
</head>
<body>
<b>杰哥の聊天室</b>
 <form action="ChatServlet" method="post">
     <p>
         用户:<input name = "user">
     </p>
     <p>
        发言:<input name = "content" >
     </p>
     <button>发送</button>

 </form>
</body>
</html>

向上攀爬的痛苦,终会在登顶时烟消云散
——ZQY

  • 24
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟0917

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值