客户端/前端:发送请求主要是通过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痿覱c8r鋱荮r唑柗嘈8y?亐昜_]?摞迂絳7獗鎦颻闟稿諿般医弤w忟?閕/?V芋H丹囫x鹪s/岢_?绝?廒kw_g?膅菌("?DR!譣w#洬嘛鞒辧G╒躒礗)?鈤燭*?]毶Emu揠踮o寒R┴o旿??靋欩">?€=峉X枸幓呋榉`畼领鴌炊暝)|熋G>鶤訩軽Y?鳎P灧玺鼢?琊[?荊嫗2鋦?┽];p捤%UX穠旿澅?.铰ず鰰隡'鼧?_?d?UR;\?嵁詘呂S??狠Jσ_諑??桍縌T礣^;^x?瑼钥p7<禅{? 膔筶俇(岄舕M乀髿 ??ebb舃胫苘韣??5ZZ搀鋊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?專#氡q1旑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("");
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(""+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中有
-
这要注意一个问题: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,说明前端代码有问题;
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)