• Servlet(三)------Javaweb


    一:thymeleaf 指令有问题

    1.检查th指令语法是否错误

    2.检查指令中是否有多余的符号

    3.检查th:text中间是否有空格

    4.检查后端代码是否有值

     Attribute name cannot be null or empty

    二:服务器给前端返回的数据,大部分情况下都是一个HTML页面,我们只是用Servlet,想要返回一个动态页面,返回的页面就只能通过字符串拼接的方式来进行构造,这是非常的不科学,使用模板引擎生成动态页面,也实现了前后端分离;

    三:前后端彻底的进行分离页面:前端代码通过Ajax的方式来和后端进行通信,后端只负责返回Json格式的数据,后端不会再去拼接页面,都是前端拿到数据之后,自己进行拼接;

    使用模板引擎,界面和逻辑进行分离(Java Servlet)

    四:模板引擎中常见的类:

    1.TemplateEngine,他是负责进行渲染,渲染指的是就是把动态的数据替换到HTML页面中的指定位置,模板引擎做得好象是考试卷子上的填空题一样,每个人在不同的卷子上填的是不同的内容,最终就展示出了不同的页面,模板引擎就是一个模板,依据这个模板就可以生成出不同的页面

    2.WebContext,这个类就是一个键值对,目标就是将HTML中模板的变量和Java代码中的变量给关联起来;

    3.ServletContextTemplateResolver叫做模板解析器对象,把之前写好的HTML模板给加载过来,并告知engine文件在哪里;

    五:模板引擎的使用流程:

    1)写一个HTML模板,对于这些可变的数据,使用一些特殊的指令来进行占个位置;

    2)针对Thymeleaf来进行初始化

    2.1创建TemplateEngine实例

    2.2通过WebContextTemplateResolver,并且设置加载模板文件的路径,设置前缀和后缀

    2.3把创建好的resolver实例关联到engine对象上

    3)针对每一个请求,分别进行模板渲染

    a)得到要进行渲染的数据(Java提前准备好一些变量)

    b)通过WebContext把HTML中的变量和Java中的变量进行关联起来

    c)通过调用engine对象的process方法,实现具体的渲染操作,也就相当于是卷子(HTML模板)和答题卡(WebContext)进行关联起来了;

    1.ServletContext(上下文)的介绍

    ServletContext是一个Servlet程序在全局储存信息的空间,服务器开始就存在,服务器关闭就销毁;每一个webapp就是tomact文件中的webapps对应的子目录;

    这个类创建的初心:在Tomact启动的时候,他会给每一个webapp(一个文件目录)都提供创建了一个ServletContext对象,而每一个单独的web-app有多个servlet,而这里面的所有servlet对象都共享一个ServletContext对象,可以共享一部分数据;

    在这里面,我们也是可以通过ServletContext实现让TemplateEngine在一个webapp中只有一个实例

    一个Tomact是一个进程,而很多webapp是进程中的一部分,如果说把Template搞成单例模式的话,webapp1和webapp2之间就会进行相互影响了,每一个webapp都要通过自己的TemplateEngine对象,来进行加载属于自己的模板文件,他们之间是不可以相互影响的,所以说我们希望每一个webapp都有属于自己的TemplateEngine对象,但是我们又希望让同一个webapp中的多个Servlet之间可以共享自己的webapp中的TemplateEngine

    在之前我们所写的代码当中,每一个Servlet都有一个TemplateEngine,这显然是不太科学的,我们希望同一个webapp中可以共享一个TemplateEngine对象;

    那么可以把TemplateEngine搞成单例模式吗?这显然是不行的,单例指的是在整个进程中只有一个实例,但是此处的TemplateEngine不应该是进程中的实例,一个Tomact就是一个进程,Template而应该是webapp级别的实例,为了做到这一点我们应该把TemplateEngine放到ServletContext中进行创建;

    2.ServletContext的具体用法----ServletContext是Tomact的内部代码new出来的,咱们是看不到的;

    它所存在的意义是可以让同一个webapp中的多个Servlet之间可以共享数据,所以ServletContext提供了一些get/set接口;所以程序员想在这多个Servlet之间共享数据,也是可以通过自定义键值对的方式来实现的

    1. 1)void setAttribute(String name,Object obj)向我们的ServletContext中设置键值对;
    2. 2)Object getAttribute(String name)根据属性名来获取到属性的值
    3. 3)void removeAttribute(),删除对应的属性

    1)咱们之前用的HttpSession可以让程序员自己去定义一些键值对来进行存储,就像是一个时间胶囊一样,我们在登陆成功的时候会存放一些数据进去,后续再进行登录进行访问的时候再通过getAttribute()方法进行取出来使用;

    2)程序员想要在这多个Servlet之间共享哪些数据,也是通过自定义键值对的方式来进行实现的;那么我们就可以想WebContext对象中来设置一些自定义的键值对,然后再别的Servlet中按照这个Key来进行访问也就可以了

    3)也就是说只要是在Java200这个web-app中创建的Servlet,咱们都是可以通过getServletContext得到同一个上下文对象

    下面我们来写一个实例:我们创建两个Servlet对象,一个是WriteServlet,向我们的web-app里面的ServletContext设置属性,另一个是ReadServlet,向我们的web-app里面的ServletContext来读取刚才设置的属性,先进行访问write再去访问read;

    一:创建WriterServlet类

    1)创建一个GET请求,请求的格式类似于,http://127.0.0.1:8080/Java200/write?message=aaa

    我们在WriteServlet中调用req.getparamter()方法,从请求参数中得到一个字符串message,通过req.getServletContext(),或者this.getServletContext(),就可以获取到当前webapp中的ServletContext对象;

    2)通过ServletContext.setAttribute()把message的值设置进去;

    3)是我们使用ReadServlet来从ServletContext来进行读取数据,就把刚才的WriteServlet存放的数据给取出来;

    当前我们写的两个Servlet对象都是用的一个webap,因为如果他们进行打包,都打到同一个war包里面了;只要是在这个webapp中创建出来的Servlet对象,在两个Servlet都是可以通过req.getServletContext得到得到同一个上下文对象WebContext;

    1. import javax.servlet.ServletContext;
    2. import javax.servlet.ServletException;
    3. import javax.servlet.annotation.WebServlet;
    4. import javax.servlet.http.HttpServlet;
    5. import javax.servlet.http.HttpServletRequest;
    6. import javax.servlet.http.HttpServletResponse;
    7. import java.io.IOException;
    8. @WebServlet("/write")
    9. //这个类负责向ServletContext中写数据
    10. //浏览器通过一个形如/write?message=aaa访问到WriteServlet,就把这个属性message=aaa这个键值对储存到ServletContext
    11. public class WriteServlet extends HttpServlet {
    12. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    13. resp.setContentType("text/html;charset=utf-8");
    14. //1从请求中获取到message参数
    15. String flag=req.getParameter("message");
    16. //2获取到当前的ServletContext对象(这个对象是Tomact在加载webapp的时候自动创建的)
    17. ServletContext servletContext= req.getServletContext();
    18. //3 向ServletContext中写入键值对
    19. servletContext.setAttribute("flag",flag);
    20. //4 返回响应
    21. resp.getWriter().write("<h3>储存message成功<h3>");
    22. }
    23. }
    24. import javax.servlet.ServletContext;
    25. import javax.servlet.ServletException;
    26. import javax.servlet.annotation.WebServlet;
    27. import javax.servlet.http.HttpServlet;
    28. import javax.servlet.http.HttpServletRequest;
    29. import javax.servlet.http.HttpServletResponse;
    30. import java.io.IOException;
    31. //用这个类来向我们的ServletContext中读取数据,这样就可以把刚才WriteServlet中储存的值读取出来
    32. @WebServlet("/read")
    33. public class ReadServlet extends HttpServlet {
    34. @Override
    35. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    36. resp.setContentType("text/html;charset=utf-8");
    37. //1获取到ServletContext对象
    38. ServletContext servletContext= req.getServletContext();
    39. //2从这里面来获取到刚才存得值
    40. String result=(String)servletContext.getAttribute("flag");
    41. resp.getWriter().write("flag"+result);
    42. }
    43. }

    1)我们进行学习ServletContext对象的初心就是想用这个对象来进行存储一个TemplateEngine对象,达到说让当前的所有webapp中的所有Servlet共用同一个TemplateEngine对象

    2)所以我们最终就需要把TemplateEngin初始化好,同时放到ServletContext对象里面,所以后续的Servlet就不必进行初始化TemplateEngin,后面需要在别的Servlet进行访问的时候,直接进行获取就可以了;

    3)为了保证每一个其他的Servlet都能够在第一时间可以获取到一个初始化好的TemplateEngin实例,我们就需要在ServletContext在创建好之后,就第一时间的给TemplateEngin进行实例化,初始化,进行保存;

    ————————————————————————————————————

    二:监听器:

    1)但是我们刚才分析了,ServletContext是由Tomact自动创建出来的,那么我们如何才可以让ServletContext创建好之后,就第一时间执行我们自己定义的的代码呢?所以Servlet就给我们提供了一组机制,叫做listener成为监听器;      因此我们就可以通过listener来监听我们ServletContext的初始化完毕的操作(ServletContext一旦创建好,就出发了监听器,执行我们自己所写的代码事件)

    2)JS中学过的onclick操作,也是一个监听器,用户一旦进行点击,就被监听到了,然后接下来进行后续的操作;

    三:实现监听器

    1)这个过程中涉及到的一些接口,我们要创建Mylistener类,就要实现ServletContextListener接口,并实现两个方法,contextInitialized和contextDestoryed;

    2)Mylistener类通过使用@webListener来进行注解修饰,才可以正确的被Tomact识别,contextInitialized的参数是ServletContextEvent对象,这个对象标识一个事件,此处我们并不进行深究;

    我们只需要可以通过ServletContextEvent.getServletContext()方法可以获取到一个ServletContext即可;

    3)当ServletContext被创建好之后,就会直接自动调用执行调用contextInitialized方法;

    1. import javax.servlet.ServletContext;
    2. import javax.servlet.ServletContextEvent;
    3. import javax.servlet.ServletContextListener;
    4. import javax.servlet.annotation.WebListener;
    5. import javax.servlet.annotation.WebServlet;
    6. @WebListener
    7. public class Mylistener implements ServletContextListener {
    8. //当ServletContext初始化之后,会立即执行这个方法
    9. @Override
    10. public void contextInitialized(ServletContextEvent servletContextEvent) {
    11. System.out.println("ServletContext已经进行了初始化,马上执行这个方法");
    12. //1 获取到ServletContext这个对象
    13. ServletContext servletContext=servletContextEvent.getServletContext();
    14. servletContext.setAttribute("message","我爱我的家");
    15. }
    16. @Override
    17. public void contextDestroyed(ServletContextEvent servletContextEvent) {
    18. }
    19. }

    1)创建一个新的类实现ServletContextListener接口,重写其中的contextInitialized方法,这个方法是在初始化完毕后被自动调用的;

    2)给新的类加上一个@webListener注解,加上这个注解之后才可以被tomact识别出来并进行加载;

    3)在方法里面获取ServletContext是通过ServletContextEvent对象来拿到的;后续就可以调用setAttribute()方法和getAttribute()方法来进行使用即可;

    4)在这里面我们就可以把TemplateEngin的初始化操作就行了,还可以进行初始化一些其他的操作和内容

    所以说我们就可以把Thymeleaf的初始化,放到contextInitialized方法里面,这样就可以保证TemplateEngine是一个webapp级别的单例

    1. import org.thymeleaf.TemplateEngine;
    2. import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
    3. import javax.servlet.ServletContext;
    4. import javax.servlet.ServletContextEvent;
    5. import javax.servlet.ServletContextListener;
    6. public class Mylistener implements ServletContextListener {
    7. @Override
    8. public void contextInitialized(ServletContextEvent servletContextEvent) {
    9. //1 初始化TemplateEngine并创建实例,并获取到ServletContext对象(通过方法中的参数获取到)
    10. ServletContext servletContext=servletContextEvent.getServletContext();
    11. TemplateEngine templateEngine=new TemplateEngine();
    12. //2 创建ServletContextTemplateResolver实例(模板解析器),并将两个类进行关联
    13. ServletContextTemplateResolver servletContextTemplateResolver=new ServletContextTemplateResolver(servletContext);
    14. servletContextTemplateResolver.setPrefix("/WEB-INF/template/");
    15. servletContextTemplateResolver.setSuffix(".html");
    16. servletContextTemplateResolver.setCharacterEncoding("utf-8");
    17. templateEngine.setTemplateResolver(servletContextTemplateResolver);
    18. //3把创建好的实例创建键值对放到ServletContext中,方便后面的Servlet进行获取,就不用在每一个Servlet里面进行初始化化操作了
    19. servletContext.setAttribute("TemplateEngine",templateEngine);
    20. System.out.println("当前webapp的TemplateEngine已经初始化完毕");
    21. //4后面的Servlet如果想要获取到templateEngine这个对象,就可以用
    22. //TemplateEngine templateEnginexx=(TemplateEngine) servletContext.getAttribute("TemplateEngine");
    23. //后续就可以调用templateEngine.process方法,HTML文件,webContext;
    24. }
    25. //ServletContext被销毁之前,会自动地执行这个方法
    26. @Override
    27. public void contextDestroyed(ServletContextEvent servletContextEvent) {
    28. }
    29. }

    四.实战案例----不用AJAX

    1)表白墙:

    在前面我们已经写了纯前端的页面版本,在后来我们又写了一个web版本(前后端进行交互的版本,前后端通过ajax的方式来发送json数据;现在我们基于一个模板引擎来进行实现;

    我们要引入模板文件,我们要在webapp中创建WEB-INF目录,在这个目录里面创建一个目录叫做template目录,把我们表白墙的前端页面方法到这个目录里面;

    1)在最外面我们要加一个form标签(里面包裹input标签),里面设置action属性,表示要跳转到那个界面,我们也是主要通过form表单来提交请求;

    之前我们写前后端分离的表白墙项目的时候,三个标签里面的值在<script>里面提取出来,并将内容打包成AJAX的方式发送给服务器,但是在现在我们通过form表单来进行提交数据指定name属性,并把数据放到queryString里面,方便后端服务器来进行获取;

    2)把JS中构造页面的片段代码去掉,换成模板引擎Thymeleaf的代码,也就是说不用再新创建元素添加到dom树上面了;

    3)把原来的button按钮改成submit才可以进行提交,才可以进行发送请求;

    4)实现服务器端的代码,内存(List)中保存消息的版本,文件中保存消息的版本,数据库中保存消息的版本;

    5)使用监听器来进行初始化模板引擎

    6)实现一个HelloWorldServlet这个类,来处理一个/HelloWorld路径这样的一个请求,分别用两个方法来实现,doGET请求用于获取消息列表,doPOST请求用于新增一个消息;

    7)当用户点击提交按钮的时候,相当于给服务器发送了一个POST请求,当我们在浏览器上面输入一个URL的时候,就相当于给服务器发送了一个GET请求,就进行加载表白墙的页面;

    我们在这里面写的doGET方法就是向List中获取里面的所有表白数据,doPOST方法就是客户端点击提交按钮之后,发送了一条表白数据,服务器收到数据之后,创建对应的对象,添加到list里面;

    前端代码

    1. <div class="father">
    2. <h1>表白墙</h1>
    3. <p>输入点击后提交,结果将显示在墙上</p>
    4. <form action="message" method="post">
    5. <div class="line">
    6. <span></span><input type="text" name="from">
    7. </div>
    8. <div class="line">
    9. <span>对谁说</span><input type="text" name="to">
    10. </div>
    11. <div class="line">
    12. <span>说什么</span>
    13. <input type="text" name="message">
    14. </div>
    15. <div class="but">
    16. <input type="submit" value="提交" class="submit">
    17. </div>
    18. </form>
    19. <!-- 添加模板这里的变量,每一个line都是表白墙上面的消息 -->
    20. <div class="line" th:each="message:${messages}">
    21. <span th:text="${message.from}"></span>
    22. <span th:text="${message.to}"></span>
    23. <span th:text="${message.message}"></span>
    24. </div>

    后端代码

    注意://处理请求的时候,也需要给请求的对象设置字符集,因为POST请求报文body格式是application/x-www......,所以说服务器在获取到请求中的内容也是URL-Encode的结果(不知道原来是啥样的),Servlet也是不知道这个encode的结果是按照UTF-8还是其他的字符集来进行编码的

    也就是说服务器在拿到数据的时候是按照utf-8的格式来进行解析的,发送的时候也要设置成utf-8的形式

    1. //先进行初始化TemplateEngine
    2. import org.thymeleaf.TemplateEngine;
    3. import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
    4. import javax.servlet.ServletContext;
    5. import javax.servlet.ServletContextEvent;
    6. import javax.servlet.ServletContextListener;
    7. import javax.servlet.annotation.WebListener;
    8. @WebListener
    9. public class Start implements ServletContextListener {
    10. @Override
    11. public void contextInitialized(ServletContextEvent servletContextEvent) {
    12. //1创建templateEngin对象,用于最终的渲染操作,并且根据这个方法的参数获取到ServletContext对象
    13. TemplateEngine engine=new TemplateEngine();
    14. ServletContext context=servletContextEvent.getServletContext();
    15. //2创建模板解析器对象,进行设置前缀和后缀以及字符编码方式
    16. ServletContextTemplateResolver resolver=new ServletContextTemplateResolver(context);
    17. resolver.setPrefix("/WEB-INF/template/");
    18. resolver.setSuffix(".html");
    19. resolver.setCharacterEncoding("utf-8");
    20. //3将汽车和加油器给进行关联到一起,将resolver对象和engine给关联到一起;
    21. engine.setTemplateResolver(resolver);
    22. //4向ServletContext中设置字符串,方便后面的Servlet进行使用的时候可以访问到TemplateEngine
    23. context.setAttribute("engine",engine);
    24. }
    25. @Override
    26. public void contextDestroyed(ServletContextEvent servletContextEvent) {
    27. }
    28. }
    29. //正式处理两个请求
    30. import org.thymeleaf.TemplateEngine;
    31. import org.thymeleaf.context.WebContext;
    32. import javax.servlet.ServletContext;
    33. import javax.servlet.ServletException;
    34. import javax.servlet.annotation.WebServlet;
    35. import javax.servlet.http.HttpServlet;
    36. import javax.servlet.http.HttpServletRequest;
    37. import javax.servlet.http.HttpServletResponse;
    38. import java.io.IOException;
    39. import java.util.ArrayList;
    40. import java.util.List;
    41. class JsonData{
    42. public String from;
    43. public String to;
    44. public String message;
    45. }
    46. @WebServlet("/message")
    47. public class HelloServlet extends HttpServlet {
    48. List<JsonData> list=new ArrayList<>();
    49. //先进行初始化数据
    50. @Override
    51. public void init() throws ServletException {
    52. JsonData jsonData=new JsonData();
    53. jsonData.from="黑猫";
    54. jsonData.to="白猫";
    55. jsonData.message="喵";
    56. list.add(jsonData);
    57. }
    58. @Override
    59. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    60. //1先进行设置返回的字符集类型
    61. resp.setContentType("text/html;charset=utf-8");
    62. //2获取到一个web-app特有的ServletContext对象
    63. ServletContext context=req.getServletContext();
    64. //3取出之前进行初始化过的TemplateEngine对象
    65. TemplateEngine engine=(TemplateEngine)context.getAttribute("engine");
    66. //4创建WebContext对象,里面主要设置的是键值对
    67. WebContext webContext=new WebContext(req,resp,context);
    68. webContext.setVariable("messages",list);//相当于是返回一个数组
    69. //5最终进行渲染操作
    70. String html= engine.process("hello",webContext);
    71. resp.getWriter().write(html);
    72. }
    73. @Override
    74. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    75. //处理请求的内容,将读到的内容进行解析,得到to,from,message,并创建出JsonData对象,并将它插入到List里面
    76. resp.setContentType("text/html;charset=utf-8");
    77. req.setCharacterEncoding("utf-8");
    78. //1先进行获取POST请求中的参数
    79. String from=req.getParameter("from");
    80. String to=req.getParameter("to");
    81. String message=req.getParameter("message");
    82. //2向list中添加数据
    83. JsonData json=new JsonData();
    84. json.from=from;
    85. json.to=to;
    86. json.message=message;
    87. list.add(json);
    88. //3进行模板渲染,进行返回
    89. ServletContext context=req.getServletContext();
    90. TemplateEngine engine=(TemplateEngine)context.getAttribute("engine");
    91. WebContext webContext=new WebContext(req,resp,context);
    92. webContext.setVariable("messages",list);
    93. String html=engine.process("hello",webContext);
    94. resp.getWriter().write(html);
    95. }
    96. }

    1)当我们触发GET请求的时候,返回的响应时一个进行渲染后的HTML界面,返回的报文Content-Type:text/html;charset=utf-8;

    2)这是当我们写了一条表白数据并提交之后,客户端给服务器发送的POST请求,显然他发送的报文格式是一个个的键值对,所以请求类型就是Content-Type: application/x-www-form-urlencoded;

    1. POST http://127.0.0.1:8080/Java200/message HTTP/1.1
    2. Host: 127.0.0.1:8080
    3. Connection: keep-alive
    4. Content-Length: 90
    5. Cache-Control: max-age=0
    6. sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="8"
    7. sec-ch-ua-mobile: ?0
    8. Upgrade-Insecure-Requests: 1
    9. Origin: http://127.0.0.1:8080
    10. Content-Type: application/x-www-form-urlencoded
    11. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 SLBrowser/8.0.0.5261 SLBChan/103
    12. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
    13. Sec-Fetch-Site: same-origin
    14. Sec-Fetch-Mode: navigate
    15. Sec-Fetch-User: ?1
    16. Sec-Fetch-Dest: document
    17. Referer: http://127.0.0.1:8080/Java200/message
    18. Accept-Encoding: gzip, deflate, br
    19. Accept-Language: zh-CN,zh;q=0.9
    20. Cookie: JSESSIONID=0E8B44B53CF17B1C314DD128BB217721
    21. from=%E6%9D%8E%E5%98%89%E6%AC%A3&to=%E6%9D%8E%E4%BD%B3%E4%BC%9F&message=%E5%A4%A7%E5%93%A5
    22. 这些都是URLEncode的结果
    1. 响应报文是这样的
    2. HTTP/1.1 200
    3. Content-Type: text/html;charset=utf-8
    4. Content-Length: 2566
    5. Date: Fri, 01 Jul 2022 13:03:57 GMT
    6. Keep-Alive: timeout=20
    7. Connection: keep-alive
    8. <!DOCTYPE html>
    9. <html lang="en">
    10. <head>
    11. <meta charset="UTF-8">
    12. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    13. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    14. <title>Document</title>
    15. </head>
    16. <body>
    17. <div class="father">
    18. <h1>表白墙</h1>
    19. <p>输入点击后提交,结果将显示在墙上</p>
    20. <form action="message" method="post">
    21. <div class="line">
    22. <span></span><input type="text" name="from">
    23. </div>
    24. <div class="line">
    25. <span>对谁说</span><input type="text" name="to">
    26. </div>
    27. <div class="line">
    28. <span>说什么</span>
    29. <input type="text" name="message">
    30. </div>
    31. <div class="but">
    32. <input type="submit" value="提交" class="submit">
    33. </div>
    34. </form>
    35. <!-- 添加模板这里的变量,每一个line都是表白墙上面的消息 -->
    36. <div class="line">
    37. <span>黑猫</span>
    38. <span>白猫</span>
    39. <span></span>
    40. </div>
    41. <div class="line">
    42. <span>黑狗</span>
    43. <span>母狗</span>
    44. <span>汪汪</span>
    45. </div>
    46. <div class="line">
    47. <span>黑猫</span>
    48. <span>白猫</span>
    49. <span>呵呵</span>
    50. </div>
    51. <div class="line">
    52. <span>李嘉欣</span>
    53. <span>李佳伟</span>
    54. <span>大哥</span>
    55. </div>
    56. </body>
    57. <style>
    58. .father{
    59. background-color:green;
    60. width:60%;
    61. margin:0 auto;
    62. box-sizing:border-box;
    63. }
    64. h1{
    65. /* 这里把h2标签当成一个字体,让字体水平居中,就要用到text-align */
    66. text-align: center;
    67. /* 这是设置内边距,也就是说设置字体和背景颜色顶部的距离 */
    68. padding:5px 0;
    69. }
    70. p{
    71. /* 控制P标签里面的字水平居中 */
    72. text-align:center;
    73. padding:5px 0;
    74. }
    75. .line{
    76. /* 设置每一行的元素,水平居中,垂直居中 */
    77. height:50px;
    78. display:flex;
    79. justify-content:center;
    80. align-items:center;
    81. }
    82. span{
    83. font-size:25px;
    84. width:120px;
    85. }
    86. input{
    87. height:25px;
    88. }
    89. .but{
    90. display:flex;
    91. }
    92. .submit{
    93. margin:0 auto;
    94. width:200px;
    95. }
    96. </style>
    97. </script>
    98. </body>
    99. </html>

     在线相册项目:

    1)我们在这里面要注意目录结构:webapp里面存放image目录,里面包含着若干张图片;webapp/WEB-INF里面含有这需要进行渲染的原HTML代码文件,以及有它同级的CSS文件

    2)我们在这里面只需写出后端代码即可(CSS样式不需要进行关心,和我们的后端代码没有任何关系),我们只需要写出服务器的代码即可,我们此处指需要进行关心的是我们要给前端页面通过模板引擎传入一个images数组,images数组里面的每一个元素是一个image对象,里面包含名字和src两个属性;

    3)这里面的关键要点:我们使用th:each来分别进行构造多个figure标签,最后把URL和name放到合适的位置上

    4)初始化模板引擎,我们也是基于listener来进行实现的,在ServletContext中创建出一个TemplateEngine实例,以备后用;

    5)写一个Servlet后端代码,写一个ImageServlet来进行展示图片界面,在这个后端代码里面,就要生成一个Image对象的数组,传给网页模板,并进行返回

    6)生成images数组的方法,给定一个指定目录,我们就需要从这个目录来进行扫描,看看都有哪些图片,根据目录中的图片信息来进行构建出一个image对象的数组

    我们在这里面给的指定目录就是/WEB-INF/image目录,看看有多少个图片构成List<Image>

    1)我们需要扫描文件路径,我们再进行扫描的时候,如何根据webapp中的image目录得到磁盘目录呢?

    我们就需要进行调用String path=context.getRealPath("/image");这事把web-app中的路径,转换成在磁盘上面的文件路径

    2)根据这个路径再扫描的过程中,看看有哪些是图片文件

    前端代码:

     

  • 相关阅读:
    Android -- 每日一问:如何理解 Android 中的 Context,它有什么用?
    mac菜单栏应用管理软件:Bartender 4 for Mac 中文激活版
    SpringBoot学习笔记(4)——B站动力节点
    LeetCode【每日一题】-栈和队列2
    Rust生态技术栈
    The Record of Reminding myself
    【操作系统】内存管理(四)—— 内存的分配与回收(2)
    一种三自由度机器人的设计(CAD+Solidworks+文档)
    基于C#的消息处理的应用程序 - 开源研究系列文章
    轻量级的开源代理服务器Tinyproxy安装与配置
  • 原文地址:https://blog.csdn.net/weixin_61518137/article/details/124550142