java EE 基础

创建java EE应用并部署

新建java EE项目

1.新建Jakarta EE项目 应用服务器可以先不选

2.用tomact 10版本的话 EE版本9.1是没有问题的

servlet版本>=5.0时 运行它的tomcat版本需要tomcat10.x版本的 具体的情况可以去看tomcat官网查

等待maven将需要的依赖都拉下来

查看一下文件的内容

index.jsp是输出Hello World!到前端 同时还插入了一个hello-servlet链接。

hello-servlet是什么?在HelloServlet.java文件中有定义

仔细看代码发现有HttpServletRequest和HttpServletResponse,这两个是Servlet API提供的HTTP请求和响应的对象,具体的执行是在底层的服务器应用(也就是我们过会要用的Tomact上执行的),后续关于请求和响应的操作我们在上层用request和response这俩参数就可以了。

观察pom.xml 我们还会发现 它打包的格式是war文件

war就是java web项目文件的打包形式 其实就是类似于java普通项目的jar文件 也相当于是一个压缩包

但是war文件的执行必须要依赖底层的web应用服务器,比如tomcat,后面我们就是把war文件放到tomcat目录下执行的。

部署项目

1.将该项目打包成为war包

2.部署tomcat 注意tomcat各个版本的运行要求

部署时直接解压即可

3.运行tomcat 进入bin目录执行startup

乱码不用管

4.尝试访问tomcat 端口8080

5.找到项目war文件 放到tomcat的webapps目录下

在这儿遇到个问题 为啥直接给我起的是9.0.105版本的tomcat啊?

因为tomcat9.0.105先安装的 环境变量的路径是它的

现在改一下它 指向tomcat10的路径

现在是切换到10.1.30版本了

没问题了 可自动解压

访问该目录

点击Hello Servlet

Servlet学习

一个java web的项目就是有多个Servlet组成的

浏览器发出的HTTP请求总是由Web Server先接收,然后,根据Servlet配置的映射,不同的路径转发到不同的Servlet。这种根据路径转发的功能我们⼀般称为dispatch。映射到 /比较特殊,相当于/*,会接收所有未匹配的路径。

有了 HttpServletRequest 和 HttpServletResponse 这两个⾼级接⼝,我们就不需要直接处理HTTP协议了。

接下来我们再去完善一下我们那个java EE的小网站

IDEA自动部署tomcat

之前我们是通过把war文件放到tomcat 的webapps目录下进行部署的

但是现在要频繁地去修改代码 每次改完重新打war包再放入tomcat的目录下这也太蠢了吧

那应该怎么做?IDEA提供了自动部署tomcat和java web进行修改和调试的方式

1.当前文件->编辑配置 点击+号新增配置 选择本地tomcat服务器

2.选择我们的tomcat文件位置去配置应用服务器

3,由于我的8080是给bp预留的 所以程序执行我就选择8081了

4,点击修复 选择java ee war:exploded

5.设置应用程序上下文 点击应用 确定。(一定要记得这一步,不然访问时就得带着javaee_war_exploded这个url了)

6.点击右上角图标运行

会自动进行浏览器的跳转

后面如果有代码修改更新的话需要点击右上角图标进行重新的部署

OK 可以开始弄了

接下来就可以去完善这web项目了

重定向与转发

我们已经编写了⼀个能处理 /hello 的 HelloServlet ,如果收到的路径为 /hi ,希望能重定向到 /hello ,可以再编写⼀个 RedirectServlet 。代码如下:

java 复制代码
@WebServlet(urlPatterns = "/hi")
public class RedirectServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //构造重定向的路径
        String name = request.getParameter("name");
        String redirectToUrl = "/hello"+(name == null ? "" : "?name="+name);
        //发送重定向的响应
        response.sendRedirect(redirectToUrl);
    }
}

抓包可以看到 当我们访问/hi时 响应包会返回302 重定向到Location: /hello

随后客户端发送/hello请求到服务端 访问到了HelloServlet

如何实现转发呢?

Forward是指内部转发。当⼀个Servlet处理请求的时候,它可以决定⾃⼰不继续处理,⽽是转发给另⼀个Servlet处理。

现在,我们已经编写了⼀个能处理 /hello 的 HelloServlet ,继续编写⼀个能处理 /morning 的 ForwardServlet。

ForwardServlet 在收到请求后,它并不⾃⼰发送响应,⽽是把请求和响应都转发给路径为 /hello 的Servlet。

代码如下:

java 复制代码
@WebServlet(urlPatterns = "/morning")
public class ForwardServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getRequestDispatcher("/hello").forward(request, response);
    }
}

抓包看的话 虽然我们访问的url是/morning 但是返回的却是HelloServlet的内容

继续哈!

Session和Cookie的使用

对于Web应⽤程序来说,我们总是通过 HttpSession 这个⾼级接⼝访问当前Session。JSESSIONID 是由Servlet容器⾃动创建的,⽬的是维护⼀个浏览器会话,它和我们的登录逻辑没有关系。即使没有登录功能,仍然可以使⽤ HttpSession 追踪⽤户。

session id 是维护浏览器会话自动创建的,和登录逻辑是没有关系的,登录逻辑给cookie中新增的key是要和这个sessionID做绑定的 也就是他俩都是cookie的内容。

写一个登录的servlet 代码如下:

登录成功后去给cookie增加一个user字段保存用户名

写⼊完毕后调⽤ flush() 却是必须的,因为⼤部分Web服务器都基于HTTP/1.1协议,会复⽤TCP连接。如果没有调⽤ flush() ,将导致缓冲区的内容⽆法及时发送到客户端。

java 复制代码
@WebServlet(urlPatterns = "/signin")
public class SignInServlet extends HttpServlet {
    //模拟一个数据库
    private Map<String, String> users = Map.of("bob", "bob123", "alice","alice123", "tom", "tomcat");

    //get请求时显示登录页面
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException{
        resp.setContentType("text/html");
        PrintWriter pw = resp.getWriter();
        pw.write("<h1>Sign In</h1>");
        pw.write("<form action=\"/signin\" method=\"post\">");
        pw.write("<p>Username: <input name=\"username\"></p>");
        pw.write("<p>Password: <input name=\"password\" type=\"password\"></p>");
        pw.write("<p><button type=\"submit\">Sign In</button> <a href=\"/\">Cancel</a></p>");
        pw.write("</form>");
        pw.flush();

    }


    // POST请求时处理⽤户登录:
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
        String name = req.getParameter("username");
        String password = req.getParameter("password");
        String expectedPassword = users.get(name.toLowerCase());
        if (expectedPassword != null && expectedPassword.equals(password)){
            // 登录成功:
            req.getSession().setAttribute("user", name);
            resp.sendRedirect("/");
        }else {
            resp.sendError(HttpServletResponse.SC_FORBIDDEN);
        }
    }
}

/路径的servlet也要写一下 /代表/* 其他没有匹配到的url都会转到它

在 AdminServlet 中,我们设置可以从 HttpSession 取出⽤户名 从而完成身份权限的校验。

java 复制代码
@WebServlet(urlPatterns = "/")
public class AdminServlet extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException{
        // 从HttpSession获取当前⽤户名:
        String user = (String) req.getSession().getAttribute("user");
        resp.setContentType("text/html");
        resp.setCharacterEncoding("UTF-8");
        resp.setHeader("X-Powered-By", "JavaEE Servlet");
        PrintWriter pw = resp.getWriter();
        pw.write("<h1>Welcome, " + (user != null ? user : "Guest") + "</h1>");

        if (user == null){
            //未登录
            pw.write("<p><a href=\"/signin\">Sign In</a></p>");
        }else {
            pw.write("<p><a href=\"/signout\">Sign Out</a></p>");
            pw.write("<h2>这是管理员后台</h2>");
        }

    }
}

未匹配到的路径会自动匹配到AdminServlet

补全signout的逻辑 登出逻辑就是从 HttpSession 中移除⽤户相关信息。

java 复制代码
@WebServlet(urlPatterns = "/signout")
public class SignOutServlet extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 从HttpSession移除⽤户名:
        req.getSession().removeAttribute("user");
        resp.sendRedirect("/");
    }

}

完整流程如下:记得删除index.jsp否则它优先执行可能会有问题

1.访问任何不存在的路径自动转到AdminServlet 但是由于未登录 会提示signin

2.点击 Sign in进行登录 账号bob先输入错误的密码bob

会禁止访问

3.输出正确的密码bob123

登陆成功

4.点击sign out 退出登录

ok了!

JSP开发

JSP是Java Server Pages的缩写,它的⽂件必须放到 /src/main/webapp 下,⽂件名必须以 .jsp 结尾,整个⽂件与HTML并⽆太⼤区别,但需要插⼊变量,或者动态输出的地⽅,使⽤特殊指令 。

写一个jsp文件:代码hello.jsp

java 复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>>Hello World - JSP</title>
</head>
<body>
    <%-- JSP Comment --%>
    <h1>Hello World!</h1>
    <p>
        <%
            out.println("Your IP address is ");
        %>
            <span style="color:red">
                    <%= request.getRemoteAddr() %>
                </span>
    </p>

</body>
</html>

有报红 但是可以运行的

因为他在idea中找不到对应的依赖 但是它在tomcat运行时tomcat中是有对应的依赖的

当然也可以在项目结构中去引入对应版本的tomcat的依赖 来消除这个问题

JSP⻚⾯内置了⼏个变量:

out:表示HttpServletResponse的PrintWriter;

session:表示当前HttpSession对象;

request:表示HttpServletRequest对象。

JSP的指令除了 外,JSP⻚⾯本身可以通过 page 指令引⼊Java类,这样后续的Java代码才能引⽤简单类名⽽不是完整类名。也可以使⽤ include 指令可以引⼊另⼀个JSP⽂件

JSP和Servlet没什么区别,因为JSP在执⾏前⾸先被编译成⼀个Servlet,这么看JSP要比Servlet高级一丢丢啊,但是本质上还是一样。

Tomcat的临时⽬录下,可以找到⼀个 hello_jsp.java 的源⽂件,这个⽂件就是Tomcat把JSP⾃动,转换成的Servlet源码。

Filter

为了把⼀些公⽤逻辑从各个Servlet中抽离出来,JavaEE的Servlet规范还提供了⼀种Filter组件,即过滤器,它的作⽤是,在HTTP请求到达Servlet之前,可以被⼀个或多个Filter预处理,类似打印⽇志、登录检查等逻辑,完全可以放到Filter中。

chain.doFilter(request, response); 写完Filter如果要继续处理请求的话 就得要加chain.daFilter 否则到filter这儿就不转发了 到不了Servlet 看到的就是空白页

新建一个Filter 软件包 写一个EncodingFilter 代码如下:

java 复制代码
@WebFilter(urlPatterns = "/*")
public class EncodingFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws  IOException, ServletException {
        System.out.println("EncodingFilter:doFilter");
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        chain.doFilter(request, response);
    }
}

去访问sign in

加断点进行调试 为了确定servlet和filter的顺序

确实是先调用了filter 然后才调用的 Signinservlet

Filter可以有针对性地拦截或者放⾏HTTP请求 比如写一段代码 MyFilter 不写chain.doFilter

java 复制代码
@WebFilter("/*")
public class MyFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain){

    }
}

看到的页面就是空白页了

所以如果Filter要使请求继续被处理,就⼀定要调⽤chain.doFilter()

Listener

Listener顾名思义就是监听器,有好⼏种Listener,其中最常⽤的是 ServletContextListener,它其实就是去监听程序是否进行初始化or关闭。

任何标注为 @WebListener ,且实现了特定接⼝的类会被Web服务器⾃动初始化

它会在整个Web应⽤程序初始化完成后,以及Web应⽤程序关闭后获得回调通知

新建一个listener软件包 写一个AppListener 代码如下

java 复制代码
@WebListener
public class AppListener implements ServletContextListener {
    // 在此初始化WebApp,例如打开数据库连接池等:
    public void contextInitialized(ServletContextEvent sce){
        System.out.println("WebApp initialized.");
    }
    // 在此清理WebApp,例如关闭数据库连接池等:
    public void contextDestroyed(ServletContextEvent sce){
        System.out.println("WebApp destroyed.");
    }
}

在网站部署和停止时都回去调用

相关推荐
ZouZou老师12 小时前
C++设计模式之适配器模式:以家具生产为例
java·设计模式·适配器模式
曼巴UE512 小时前
UE5 C++ 动态多播
java·开发语言
VX:Fegn089512 小时前
计算机毕业设计|基于springboot + vue音乐管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
程序员鱼皮13 小时前
刚刚,IDEA 免费版发布!终于不用破解了
java·程序员·jetbrains
热心市民蟹不肉13 小时前
黑盒漏洞扫描(三)
数据库·redis·安全·缓存
GIS数据转换器13 小时前
综合安防数智管理平台
大数据·网络·人工智能·安全·无人机
steins_甲乙13 小时前
C++并发编程(3)——资源竞争下的安全栈
开发语言·c++·安全
2501_9159090613 小时前
iOS 反编译防护工具全景解析 从底层符号到资源层的多维安全体系
android·安全·ios·小程序·uni-app·iphone·webview
Hui Baby13 小时前
Nacos容灾俩种方案对比
java