在线相册的前后端交互

纯前端的代码

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);;
}

展示效果

1

通过模板引擎实现提交相册的功能

拟好思路

POST 请求:从客户端往服务器上传本地图片
POST 请求通过 form 表单,来实现提交(点击提交按钮)

GET 请求: 客户端从服务器中显示图片数据
GET 请求不需要通过代码构造请求(开启 / 刷新浏览器页面)

POST 响应:服务器接收客户端上传过来的图片,返回一个 html 页面
POST 响应通过 Servlet 代码完成,并重定向到 GET 响应的页面中。

GET 响应:服务器给客户端返回一个 html 页面
GET 响应通过 Servlet 代码以及 html 模板文件来实现

搭建项目环境

0

服务器端代码

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>

最终展示结果

5

总结流程

  1. 搭建项目环境(引入依赖,创建好目录)
  2. 把纯前端的代码拷贝到项目中
  3. 基于纯前端代码,稍作改动,实现 html 页面模板
  4. 基于 Listener 监听器,初始化模板引擎,在 ServletContext 中,构造一个TemplateEngine 实例,以备后用
  5. 实现 Servlet 业务代码,通过 doGet 方法处理 GET 请求,doPost 方法处理 POST 请求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十七ing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值