在线相册的前后端交互
纯前端的代码
index.html 文件
<head>
<meta charset="UTF-8">
<title>相册</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<figure class="sample">
<img src="image/1.jpg" alt="sample1" />
<figcaption>
<div>
<h2>Online</h2>
<h4>Eternity Moment</h4>
</div>
</figcaption>
<a href="image/1.jpg"></a>
</figure>
<figure class="sample">
<img src="image/2.jpg" alt="sample2" />
<figcaption>
<div>
<h2>Online</h2>
<h4>Eternity Moment</h4>
</div>
</figcaption>
<a href="image/2.jpg"></a>
</figure>
<figure class="sample">
<img src="image/3.jpg" alt="sample3" />
<figcaption>
<div>
<h2>Online</h2>
<h4>Eternity Moment</h4>
</div>
</figcaption>
<a href="image/3.jpg"></a>
</figure>
</body>
css 文件
/* sample 部分的整体样式 */
.sample {
font-family: 'Raleway', Arial, sans-serif;
position: relative;
overflow: hidden;
margin: 10px;
min-width: 230px;
max-width: 315px;
width: 100%;
color: #ffffff;
text-align: center;
font-size: 16px;
background-color: #000000;
}
.sample *,
.sample *:before,
.sample *:after {
-webkit-box-sizing: border-box;
box-sizing: border-box;
/* 当过了 0.55s 过渡效果 */
-webkit-transition: all 0.55s ease;
transition: all 0.55s ease;
}
/* 图片部分的样式 */
.sample img {
max-width: 100%;
backface-visibility: hidden;
vertical-align: top;
}
/* figcaption 用作文档中插图的图像,带有一个标题 */
.sample figcaption {
position: absolute;
bottom: 25px;
right: 25px;
padding: 5px 10px 10px;
}
/* 绘制线条 */
.sample figcaption:before,
.sample figcaption:after {
height: 2px;
width: 400px;
position: absolute;
content: '';
background-color: #ffffff;
}
/* 上面一条线 */
.sample figcaption:before {
top: 0;
left: 0;
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
/* 下面一条线 */
.sample figcaption:after {
bottom: 0;
right: 0;
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
/* 绘制线条 */
.sample figcaption div:before,
.sample figcaption div:after {
width: 2px;
height: 300px;
position: absolute;
content: '';
background-color: #ffffff;
}
/* 左面一条线 */
.sample figcaption div:before {
top: 0;
left: 0;
-webkit-transform: translateY(100%);
transform: translateY(100%);
}
/* 右面一条线 */
.sample figcaption div:after {
bottom: 0;
right: 0;
-webkit-transform: translateY(-100%);
transform: translateY(-100%);
}
/* 文字部分 */
.sample h2,
.sample h4 {
margin: 0;
text-transform: uppercase;
}
.sample h2 {
font-weight: 400;
}
.sample h4 {
display: block;
font-weight: 700;
background-color: #ffffff;
padding: 5px 10px;
color: #000000;
}
.sample a {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
/* 当鼠标放到图片时的效果, .hover 仅演示需要,可自行取消 */
.sample:hover img,
.sample.hover img {
zoom: 1;
filter: alpha(opacity=50);
-webkit-opacity: 0.5;
opacity: 0.5;
}
.sample:hover figcaption:before,
.sample.hover figcaption:before,
.sample:hover figcaption:after,
.sample.hover figcaption:after,
.sample:hover figcaption div:before,
.sample.hover figcaption div:before,
.sample:hover figcaption div:after,
.sample.hover figcaption div:after {
-webkit-transform: translate(0, 0);
transform: translate(0, 0);
}
.sample:hover figcaption:before,
.sample.hover figcaption:before,
.sample:hover figcaption:after,
.sample.hover figcaption:after {
/* 过渡延时 0.15s */
-webkit-transition-delay: 0.15s;
transition-delay: 0.15s;
}
/* 背景仅演示作用 */
html {
height: 100%;
}
body {
background-color: #212121;
display: flex;
justify-content: center;
align-items: center;
flex-flow: wrap;
margin: 0;
height: 100%;
}
.link {
color: white;
text-decoration: none;
/* 加上简单的过渡效果 */
transition: all 0.5s;
}
.link:hover {
background-color: rgb(149, 147, 147);;
}
展示效果
通过模板引擎实现提交相册的功能
拟好思路
POST 请求:从客户端往服务器上传本地图片
POST 请求通过 form 表单,来实现提交(点击提交按钮)
GET 请求: 客户端从服务器中显示图片数据
GET 请求不需要通过代码构造请求(开启 / 刷新浏览器页面)
POST 响应:服务器接收客户端上传过来的图片,返回一个 html 页面
POST 响应通过 Servlet 代码完成,并重定向到 GET 响应的页面中。
GET 响应:服务器给客户端返回一个 html 页面
GET 响应通过 Servlet 代码以及 html 模板文件来实现
搭建项目环境
服务器端代码
ThymeleafConfig 类
ThymeleafConfig 类用于初始化 TemplateEngine 模板引擎。
@WebListener
public class ThymeleafConfig implements ServletContextListener {
/**
* ServletContext 初始化后,会调用此方法
*/
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
ServletContext context = servletContextEvent.getServletContext();
// 1. 创建一个 TemplateEngine 的实例
TemplateEngine engine = new TemplateEngine();
// 2. 创建一个 ServletContextTemplateResolver 的实例
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(context);
resolver.setPrefix("WEB-INF/template/");
resolver.setSuffix(".html");
resolver.setCharacterEncoding("UTF-8");
// 3. 把 resolver 和 engine 关联起来
engine.setTemplateResolver(resolver);
// 4. 把创建好的 engine 对象放到 ServletContext 对象中去
context.setAttribute("engine", engine);
System.out.println("TemplateEngine 初始化完毕!");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
}
LoadServlet 类
LoadServlet 类 用于处理 GET 请求,并做出 GET 响应。
class Photo {
public String name;
public String url;
}
@WebServlet("/load")
public class LoadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset = UTF-8");
List<Photo> photoList = loading();
String linkSubmit = "http://127.0.0.1:8080/PhotoAlbum/upload.html";
// 将前端代码 ${photos} 和 后端代码 photos 联系起来
WebContext webContext = new WebContext(req, resp, this.getServletContext());
webContext.setVariable("photos", photoList);
webContext.setVariable("link_submit", linkSubmit);
// 从 ServletContext 对象中取出初始化后的 TemplateEngine 实例
ServletContext context = this.getServletContext();
TemplateEngine engine = (TemplateEngine) context.getAttribute("engine");
// 完成模板的最后渲染
// 下面的 photos_template 表示的是模板文件,去掉了 html 后缀
String html = engine.process("photos_template", webContext);
resp.getWriter().write(html);
}
/**
* loading 方法用来扫描 /webapp/image 这个目录,并将所有的文件当作对象,放入一个顺序表中
*/
private List<Photo> loading() {
List<Photo> photoList = new ArrayList<>();
// /webapp/image 这个目录 是当前存放在项目中的目录,并不是绝对路径
ServletContext context = this.getServletContext();
// 我们需要通过 getRealPath 这个方法,将 webapp 下面的目录,转换成磁盘的绝对路径
String path = context.getRealPath("/image");
// 如果不理解绝对路径,打印出来,看一下,就明白了,其实是从系统盘开始,一直往下搜寻而已
System.out.println(path);
// 根据 path 路径,就可以看里面有哪些图片文件了
File root = new File(path);
// listFiles 方法,返回一个 File 类型的数组
File[] files = root.listFiles();
for (File f : files) {
Photo photo = new Photo();
photo.name = f.getName();
photo.url = "image/" + f.getName();
photoList.add(photo);
}
return photoList;
}
}
UploadServlet 类
UploadServlet 类 用于处理 POST 请求,并做出 POST 响应。
@MultipartConfig
@WebServlet("/upload")
public class UploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 从 req 对象中,读取 Part 对象 ( 这其实就是在读取 HTTP 请求上传过来的图片 )
Part part = req.getPart("photo");
// 2. 把图片放到指定路径中
// 这里依然要获取磁盘上的绝对路径
ServletContext context = this.getServletContext();
String path = context.getRealPath("/image");
part.write(path + "/" + part.getSubmittedFileName());
// 3. 从上传页面重定向加载页面
resp.sendRedirect("load");
}
}
客户端代码
form 表单用于提交图片
form 表单用于提交图片,也就是发起 POST 请求。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>上传图片</title>
</head>
<body>
<form action="upload" method="POST" enctype="multipart/form-data">
<input type="file" name="photo">
<input type="submit" value="提交图片">
</form>
</body>
</html>
html 模板文件
虽然 html 模板文件,说起来是一个崭新的模板,但它的代码逻辑实际上是根据自己的需求,对原来纯前端代码进行了改进。可以对比前后两个的改动之处。
此外,这里的 html 模板文件,一定要与服务器端的代码约定好,每一个变量、路径…都需要约定好。否则,页面的最终显示效果就达不到预期要求,很大可能,浏览器直接就会报错,这里就不演示了…
最后,我们一定要明确,这样的 html 模板文件是用来干什么的?
在 Web 开发中,它就是用来,让服务器端返回一个复杂的 html 页面的,模板的唯一意义:也就是被服务器端用代码进行覆盖的!
只有深刻理解了模板文件的意义,才能够使用 Java 代码将其联系起来,这也是基于模板引擎实现 Web 开发最关键所在。
<head>
<meta charset="UTF-8">
<title>相册</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<!-- 通过 th:each 循环生成多个 figure 标签, 每个标签就对应着一张图片 -->
<figure class="sample" th:each="photo : ${photos}">
<img th:src="${photo.url}" alt="sample1" />
<figcaption>
<div>
<h2 th:text="${photo.name}"></h2>
</div>
</figcaption>
<a th:href="${photo.url}"></a>
</figure>
<!-- 下面的链接用于将 GET 请求 和 POST 请求联系起来 -->
<a th:href="${link_submit}" class="link">点击提交图片</a>
</body>
最终展示结果
总结流程
- 搭建项目环境(引入依赖,创建好目录)
- 把纯前端的代码拷贝到项目中
- 基于纯前端代码,稍作改动,实现 html 页面模板
- 基于 Listener 监听器,初始化模板引擎,在 ServletContext 中,构造一个TemplateEngine 实例,以备后用
- 实现 Servlet 业务代码,通过 doGet 方法处理 GET 请求,doPost 方法处理 POST 请求。