模板引擎

模板引擎,第1张

1.Servlet的最后一个实战项目:实现一个上传文件的功能

客户端/前端:发送请求主要是通过form表单来进行的,form表单中有一个input type="file"类型的元素;

1)前端这里面,使用form表单,实现一个文本选择框,里面要写一些属性,enctype="multipart/form-data" name="";

2)后端这里面,使用HttpServletRequest中的getPart方法,参数和前端这里面的name属性一致,getPart就得到了一个文件对象,就包含了文件的名字,大小,类型等属性

服务器的代码:

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
@MultipartConfig//加上这个注解,SerVlet才可以读到正确的文件内容,没有这个注解就会出现500
@WebServlet("/upload")
public class HelloServlet3 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  //1从req对象中读取Part对象
       Part part= req.getPart("MyImage");//这里面写的参数必须要和form表单中所存放的name属性要相同
  //2读取Part中的一些内容
        System.out.println(part.getSubmittedFileName());//读取上传的真实的文件名
        System.out.println(part.getContentType());//读到上传文件的类型
        System.out.println(part.getSize());//读到上传文件的大小
  //3把文件写到指定的路径中
        part.write("d:/前端代码/MyImage.jpg");
   //4 返回一个响应
   resp.getWriter().write("upload:OK");
    }


}

客户端的代码:


    

这是用Fidder抓包的POST请求:

POST http://127.0.0.1:8080/javaweb/upload HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Content-Length: 67953
Cache-Control: max-age=0
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="8"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
Origin: http://127.0.0.1:8080
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryFHuL8e5jqCiqy0Ay
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.4153 SLBChan/103
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
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://127.0.0.1:8080/javaweb/upfile.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=14ED82B2264584D2E12E4CD6F7C0B8AC

------WebKitFormBoundaryFHuL8e5jqCiqy0Ay
Content-Disposition: form-data; name="MyImage"; filename="灞忓箷鎴浘 2022-04-26 102914.png"
Content-Type: image/png

塒NG

   
IHDR   ?   ?   
?   sRGB ?   gAMA  睆
黙   	pHYs  %  %IR$?  DATx^越g€e譛%糬惟r觋X漑j祌禿K?c36?f 3囫燼0a挶?乩€q朵CKj﹕使赍钓陽%3邿橲}w呓鐬诚k?Mo~{?犃孎鸣T鈗漎???晖k筑讎?Kj豼<霄齶羠砻)基∵?.8??缬?牢暝Z=澇?v呛9泅?鮙敮磛n?籱韜朾鐪k??蒂牭{頊s錅_?喂`砣9端渿:?琰局^]粗鹹頎Y唖唗X鹺醳鹒曲祥7'5?]x挖v隆@?鏞?脬曮?z?蠠v?訁uY$;~?4?xp?炘轶?/8袷s硎媪?.VWW懴???5鱖瓎n?>?B?ZZZ000€_|閠W\q痿覱c8r鋱荮r唑柗嘈8y?亐昜_]?摞迂絳7獗鎦颻闟稿諿般医弤w忟?閕/?V芋H丹囫x鹪s/岢_?绝?廒kw_g?膅菌("?DR!譣w#洬嘛鞒辧G╒躒礗)?鈤燭*?]毶Emu揠踮o寒R┴o旿??靋欩">?€=峉X枸幓呋榉`畼领鴌炊暝)|熋G>鶤訩軽Y?鳎P灧玺鼢?琊[?荊嫗2鋦?┽];p捤%UX穠旿澅?.铰ず鰰隡'鼧?_?d?UR;\?嵁詘呂S??狠Jσ_諑??桍縌T礣^;^x?瑼钥p7<禅{? 膔筶俇(岄舕M乀髿 ??ebb舃胫苘韣??5ZZ搀鋊0?g螛皙L=_楠K.翓??P$畴檅r	?隆梍FG簬OW\??!?Ao趥摟莗?奏骚熉5W]庂??=哅埙牭?[秿赓鐬@[k'ff?59儔馡<麬謌虅澍?8w?螢??U?gN钞骕X?%U.M簌隮D櫱鷁*棇!啁?p
E莉?决傧岫?紨)b菫d镐騷阁禰鹌踤袍喏Vx葪w^覊[O<嶗?奺4*?P?g梣韝bj
+?检#趿+聀1c
蓤Q詶第繛Q潳k/羹q氆?'贀汪^謴&曽?徸齩点?嬕椬硝5脿43? W伈魉?*a摉?貂鯔p舎?8?b>	曃酷
o莉虿	鍥唿f糒FHd2&|:晻隋,倾q躷覯fE? "?夯籑恥瑀d?專#氡q1旑U櫧絵V噰~? 6n貈铖<寒趬?猫籮樸髜鹄給?$B???墲籿 oE楞?謳肎O#熕`鄱=更搽慗u⒖w雴?
ⅶ?潩韍飄CKk娍'姓諄逓nt3黥t〗?馜?>氏榏墕I??"
H'
闒*侚繌S?穛礞6渻泇淬嗅:c$?
HU瑺F欧膊7襄雚L-挞sp#ZOa9纰?鄪铛槞熋橨壿陠清1E睥?鸺0S吢瓦}暾拷?^澼~G銶靬羺識+痼卢蟑|w吸霋蓰爛奐3
f?s窕曱u粮?Uj|`?≯OB"?嫤,K!!曅IPu澿ー拔赦迆&X鄯o7!B戠凗 v宯C礬羴g熋塩荘?p骋昩	方駦v]?7劤梁x)P骴围焳7o聣S'q锓锩??╞7锍燐[x(?鸟?瘌c廰缥濜驐繉__E笿KF鎈蔳唳?]'2??腗踫*U ?痆徚?B蓩sGG'ㄅ攭纂?^酬.逻
侮?耀id砓?枟枒醧仏称6e?荀輠裒⑨ 祌>?粭?G?J(SQ?i?椺?a渔
8w?*?W?C?ˊWq?竲藇磠p撰鸩峂:?[馇匑?禶蝕齒?of繵畊S
?rhf7玢忑戩鸿籟筃z棞博t植軨H猄L謳/?黄棍G?讐
玳稏~劄k蛇╕[}き>?@:D挣欜{蚜?尺昜W]āF硝?譙χ
2.模板引擎: 1)背景介绍:

Servlet只是进行前后端交互的API,Servlet本质上并不关心,服务器给页面返回一个啥样的东西

很多时候我们希望给客户端返回一个HTML页面,并且我们希望HTML中的数据是通过计算得到的;这个HTML并不是一个静态页面,而是一个实时变化的;

如果没有模板引擎,我们经常通过字符串拼接的方式来进行;

例如我们来构建一个前后端交互的过程,客户端向服务器发送了一个GET请求,里面有QueryString属性,里面又包含了name属性,我们希望根据不同的queryString中的name的值,最终在页面返回一个name的值,或者通过StringBuider来进行创建,这就太复杂啦。。。代码如下:

@WebServlet("/html")
public class HelloServlet3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name=req.getParameter("name");
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().write(""+name+"");
    }
}
2)下面我们来写一个web版本的猜数字页面;

2.1首先我们要约定好前后端进行交互的方式

GET/guessNum,通过这个请求,来生成一个页面(页面里面就包含基本猜数字的页面),同时在服务器这里面进行初始化,让服务器生成一个1-100之间要去猜的数字;

POST/guessNum,(这是处理一次猜的过程,页面上有一个输入框,还有一个提交按钮,点击提交按钮),就会把输入的内容交给服务器(从这里开始真正的发送了一个POST请求);服务器收到这个数据之后,判断一下这个数据是不是猜对了,返回一个界面包含猜打了猜小了,还是猜对了

2.2我们要写一个GuessNumServlet,就要关联上/guessNum这个路径;

1)先实现一个doGET方法,来处理第一个交互接口

2)在实现一个doPOST方法,实现第二个交互接口;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Random;

@WebServlet("/guessNum")
public class HelloServlet3 extends HttpServlet{

    //先获取到页面的初始情况,并且初始化,生成一个随机的数字
    private int num=0;
    //count表示要猜的数字
    private int count=0;
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  //1 先生成一个随机的数字
        //这里面必须要设置一个返回的body的类型,要不然默认就会返回一个HTML标签
        resp.setContentType("text/html;charset=utf-8");
        Random random=new Random();
         num= random.nextInt(100)+1;
         count=0;
         StringBuilder stringBuilder=new StringBuilder();
         //在返回页面中的form表单中加上method=POST是为了后续可以触发POST请求,
         stringBuilder.append("
"); stringBuilder.append(""); stringBuilder.append(""); stringBuilder.append("
"); resp.getWriter().write(stringBuilder.toString()); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1先从我们的请求中,读去用户提交的输入框的内容 String integer=req.getParameter("num"); resp.setContentType("text/html;charset=utf-8"); int guessnum=Integer.parseInt(integer); String result=""; //2进行比较 if(num==guessnum) { result="你猜对了"; }else if(num>guessnum) { result="你猜小了"; }else{ result="你猜大了"; } //3猜的次数增加 count++; StringBuilder stringBuilder=new StringBuilder(); //在返回页面中的form表单中加上method=POST是为了后续可以触发POST请求, stringBuilder.append("
"); stringBuilder.append(""); stringBuilder.append(""); stringBuilder.append("
"); stringBuilder.append(""+result+""); stringBuilder.append("当前猜了:"+count+"次"+""); resp.getWriter().write(stringBuilder.toString()); } }

通过刚才的案例,我们知道拼接字符串的方式是很不靠谱的,模板引擎就是可以让我们自己来写一个html界面,固定的位置都不变;把一些不固定的地方使用一些特殊符号占位,在程序运行当中,再把占位符给换掉;

3)模板引擎的具体用法:

创建文件的位置:在WEB-INF中创建template文件,再从这个文件里面创建创建一个新的HTML文件;

1)我们先写一个模板文件,其实上就是一个HTML文件,只不过是把一些有用的数据摘出来了;
2)编写一个类,调用里面的doGET方法,就可以把当前这个模板给返回回来

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

当前的模板引擎是一个对象,解析器是一个对象,这样分开的目的是模板引擎可以同时安排上多个不同类型的解析器;

import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("helloworldhh")
public class HelloServlet3 extends HttpServlet {
         //这个就是我们使用模板引擎中最核心的类
    private TemplateEngine engine=new TemplateEngine();
    public void init() throws ServletException{
        //完成Thymeleaf的初始化 *** 作,还要创建一个模板解析器对象,this.getServletContext
        //Context的意思是上下文,每一个webapp里面都有一个Context,一个webapp里面可以有多个Servlet对象,这些Servlet对象共用一个Context对象
        //Context对象是Tomact加载webapp的时候所创建出的一个对象,Tomact在webapps中有多个webapp,每一个webapp都会创建出对应的Context对象;
        //每一个目录都可以看成是一个webapp,所以说同一个webapp里面的若干个Servlet共用一个Context对象
        //所以这里面的getServletContext就是获取到这里面的Context对象
        ServletContextTemplateResolver resolver=new ServletContextTemplateResolver(this.getServletContext());
        //让模板解析器来加载文件,先设置前缀,再设置后缀,也就是说当前的目录中凡是带。html的文件都会被加载出来
        resolver.setPrefix("/WEB-INF/template/");
        resolver.setSuffix(".html");
        resolver.setCharacterEncoding("utf-8");
        //把解析器对象设置到engine对象中;
        engine.setTemplateResolver(resolver);
        //他的关联主要是为了告诉模板引擎,当前要加载那些文件,以什么样的形式加载;
        //模板引擎是一辆汽车,模板解析器是一辆发动机,最终要把发动机关联到汽车上
    }
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //0.在进行模板渲染之前(把刚才写的html代码中的message变量进行替换),要先进行初始化,况且这个初始化 *** 作只执行一次即可,所以我们把它放到init()方法中进行
    //1.处理请求,先从参数中读取传过来的message的值(queryString中读取)
        String str1=req.getParameter("query");
    //2把当前从请求中的读取出来的message的值和模板中的${message}给关联起来
        WebContext webContext=new WebContext(req,resp,getServletContext());
        webContext.setVariable("message",str1);
        //这就会把str1中的值放到h3标签中
    //3最终进行渲染,第一个参数就是HTML文件的前缀
    String html=engine.process("hello",webContext);
    resp.getWriter().write(html);
    }
}

类中的参数确定(背):

1)private TemplateEngine templateEngine=new TemplateEngine();
这里面没有参数;
2)ServletContextTemplateResolver resovler=new ServletContextTemplateResovler()
里面要传的参数是this.getServletContext();
3)WebContext webContext=new WebContext()
里面要传req,resp,getServletContext;

使用ThymeLeaf的流程:

1)先编写HTML模板文件,放到固定的目录中;

2)创建出一个TemplateEngin实例,这是模板引擎中最核心的类,最重要进行替换,相当于汽车;

3)再创建一个ServletContextTemplateResolver实例,并把要指定加载的文件路径和类型通过setPrefix(指定路径)和setSuffix(指定文件类型,html文件),并通过setCharacterEncodding来指定字符编码方式,相当于是汽车的导航仪,告诉气车到哪里执行工作

4)再通过engin.setTemplateResovler(),这个方法把上面的两个实例进行关联起来;把导航和汽车关联起来;

5)上面的过程都是在init()中做的初始化 *** 作,下面正是调用doGET方法;

6)再创建一个实例WebContext对象,先获取到queryString中的值,在调用其中的setVariable将HTML中的变量("${message}")和第一个参数"message"进行替换,第二个参数把queryString中的值放到标签中,想象成键值对结构;

7)再调用engine的process方法来完成模板中内容的替换,参数是HTML文件名(源文件),WebConText(替换之后的文件)对象

8)本质上来说把变量的值替换到HTML中,主要就是HTML中的变量字符串和java代码中的字符串进行替换

  

4)实战项目:重新写一个猜数字界面

1)当我们在浏览器上面输入一个URL路径的时候,就相当于给服务器发送了一个GET请求,此时是第一次访问只需将newGame设成true即可,不需要显示出访问次数和猜的情况;

2)当我们在浏览器上面提交一个我们所要猜的数字之后,就会触发POST请求,就会把我们刚才才的数字发送过去

import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Random;

@WebServlet("/guessNum")
public class HelloServlet3 extends HttpServlet{
    private TemplateEngine templateEngine=new TemplateEngine();

    @Override
    public void init() throws ServletException {
        ServletContextTemplateResolver servletContextTemplateResolver=new ServletContextTemplateResolver(this.getServletContext());
        servletContextTemplateResolver.setPrefix("/WEB-INF/template/");
        servletContextTemplateResolver.setSuffix(".html");
        servletContextTemplateResolver.setCharacterEncoding("utf-8");
        templateEngine.setTemplateResolver(servletContextTemplateResolver);
    }

    //先获取到页面的初始情况,并且初始化,生成一个随机的数字
    private int num=0;
    //count表示要猜的数字
    private int count=0;

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1 先生成一个随机的数字
        //这里面必须要设置一个返回的body的类型,要不然默认就会返回一个HTML标签
        resp.setContentType("text/html;charset=utf-8");
        Random random=new Random();
        num= random.nextInt(100)+1;
        count=0;
      //2返回一个HTML页面,这时开始一局新的游戏
        WebContext webContext=new WebContext(req,resp,getServletContext());
        webContext.setVariable("newGame",true);
      String html=  templateEngine.process("hello",webContext);
        //要把hello文件里面的值替换成webContext中的内容
        resp.getWriter().write(html);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1先从我们的请求中,读去用户提交的输入框的内容
        String integer=req.getParameter("num");
        resp.setContentType("text/html;charset=utf-8");
        int guessnum=Integer.parseInt(integer);
        String result="";
        //2进行比较
        if(num==guessnum)
        {
            result="你猜对了";
        }else if(num>guessnum)
        {
            result="你猜小了";
        }else{
            result="你猜大了";
        }
        //3猜的次数增加
        count++;
         WebContext webContext=new WebContext(req,resp,getServletContext());
         webContext.setVariable("newGame",false);
         webContext.setVariable("count",count);
         webContext.setVariable("result",result);
         String html=templateEngine.process("hello",webContext);
         System.out.println(html);
         resp.getWriter().write(html);
    }
}

前端代码:

 

常见的Thymeleaf中的命令:

1)th:text;在标签体的表达式获取到的文本内容
2)th:if;当表达式为真的时候显示内容,为假时不显示
3)th:[HTML标签属性]设置任意的HTML标签中属性的值
这是就可以在模板中显示:th:src="${url}",这样就可以直接在java代码中进行关联
String path="d:/html文件";
就可以写成webContext.setVariable("url",path);
像a标签的href属性也是这样;
4)th:each循环渲染,有时服务器提供的数据可能是一个数组,list这时就可以通过这个属性来把数组中的每一个元素都进行渲染,最终以循环的方式展现出来
5)实战项目:实现一个显示电话号码的简单案例

1)先去写一个模板界面,主要里面有一个ul,ul中有

  • 标签,
  • 标签里面有标签,li标签里面的span中就包含了一个完整的记录,姓名+电话

     

    这要注意一个问题:java代码中传过来一个persons数组,里面的每个东西就是一个person对象,person对象里面有两个成员,name,phone;

    th:each="person:"${persons}",person就相当于取到persons中的每一个元素了,在进行后面的代码,就可以通过${person.name}和¥{person.phone}来访问person对象中的属性了;

    import org.thymeleaf.TemplateEngine;
    import org.thymeleaf.context.WebContext;
    import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    class Person{
        public String name;
        public String phone;
    
        public Person(String name, String phone) {
            this.name = name;
            this.phone = phone;
        }
    }
    
    @WebServlet("/helloyou")
    public class HelloServlet3 extends HttpServlet {
       private TemplateEngine templateEngine=new TemplateEngine();
    
        @Override
        public void init() throws ServletException {
            ServletContextTemplateResolver servletContextTemplateResolver=new ServletContextTemplateResolver(this.getServletContext());
       servletContextTemplateResolver.setPrefix("/WEB-INF/template/");
       servletContextTemplateResolver.setSuffix(".html");
       servletContextTemplateResolver.setCharacterEncoding("utf-8");
       templateEngine.setTemplateResolver(servletContextTemplateResolver);
        }
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            WebContext webContext=new WebContext(req,resp,getServletContext());
            resp.setContentType("text/html;charset=utf-8");
            List list=new ArrayList<>();
            list.add(new Person("李佳伟","12503487e"));
            list.add(new Person("李佳鑫","12506788a"));
            webContext.setVariable("persons",list);
            templateEngine.process("hello",webContext, resp.getWriter());
    
        }
    }

    如果出现了500,说明前端代码有问题;

    欢迎分享,转载请注明来源:内存溢出

    原文地址: http://outofmemory.cn/langs/798381.html

  • (0)
    打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
    上一篇 2022-05-06
    下一篇 2022-05-06

    发表评论

    登录后才能评论

    评论列表(0条)

    保存