基于JavaWeb的美妆消费辅助决策网站全解析

做毕设,我觉得最怕的不是技术难,而是题目没选好。题目选好了,后面所有事情都顺。这个题号07467的“基于JavaWeb的美妆消费辅助决策网站”,名字看着有点长,但拆开看其实特别清晰:技术栈是JavaWeb,业务是美妆消费辅助决策,交付物是一个可以跑起来的完整网站。我第一次看这个题的时候就觉得它讨巧——美妆是当下年轻人聊天绕不开的话题,消费决策又是一个非常真实的痛点,把它做成一个JavaWeb项目,既能用到Servlet、JSP、MySQL这些基本功,又有足够具体的业务故事可以讲。

这种项目适合谁?一个是正在选毕设题目的计算机专业学生,另一个是想用一个完整项目提升简历竞争力、但没想好做什么的Java自学者。它难度不大,不需要你会微服务、不需要你会分布式,但你得把JavaWeb的核心知识串一遍:前端页面、Servlet控制层、后端业务逻辑、数据库操作,缺一不可。如果你正好也需要一个带源码的完整案例来参考,那这篇内容基本就是把整个项目思路和实现过程从头到尾拆给你看。

下面我从设计思路、技术选型、核心模块、部署运行、常见排查以及升级扩展这几个方面,把整件事讲透。代码只挑关键片段展示,完整源码在项目包里都有,如果你想跑起来,按第四章的步骤操作就行。

1. 项目定位与核心需求拆解

1.1 美妆消费决策场景下的真实痛点

先说业务。美妆消费者在买东西之前,其实是有很多犹豫的。我接触过不少做这类课题的同学,他们一开始都把项目做成了“美妆商城”,上来就是商品列表、加入购物车、下单支付,结果做完发现这不过是一个电商系统换了个皮,没有任何“辅助决策”的影子。

那“辅助决策”到底辅助什么?我认为核心要解决三个问题。

第一,这个产品适不适合我。每个人的肤质不一样,油皮和干皮对同一款面霜的感受完全不同。这个需求落到系统里,就是肤质测评和产品-肤质匹配。

第二,它的真实口碑怎么样。现在网上种草和广告混在一起,用户需要一个能沉淀真实评价的地方。对应功能就是评论和评分。

第三,价格是不是合理,值不值得现在买。对应功能就是价格记录、价格比较。

所以这个项目的核心功能设计不是从“管理员要管理什么”出发,而是从“用户在下单前需要知道什么”出发。这也是这个题目在答辩时最值得讲的地方:你有明确的业务问题意识,而不是单纯在做CRUD。

1.2 功能清单与角色划分

整个系统我按用户角色拆成两个端。

用户端功能包括:注册登录、肤质测评、美妆产品浏览与搜索、产品详情查看、成分解析、产品收藏、评论评分、价格记录查看。

管理员端功能包括:美妆产品管理(增删改查)、产品分类管理、用户管理、评论审核管理、价格信息维护。

功能数量上,不多不少,刚好符合毕设要求。有的同学喜欢把功能堆到十几个页面,但功能越多,代码越容易乱,答辩时也讲不清楚。这里的取舍原则是:基础增删改查必须有,但一定要有一个核心业务逻辑作为亮点。这套系统里的亮点就是肤质测评与推荐匹配、成分关键词解析这两个模块,它们不复杂,但能体现你的思考。

需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。

2. 技术选型与架构设计

2.1 为什么还是选了JSP+Servlet,而不是Spring Boot

很多同学会纠结这个问题:现在企业里都用Spring Boot了,毕设还用JSP+Servlet是不是太老?

我的建议是:看清题目再决定。题目明确写的是“基于JavaWeb”,那么最合理的理解就是用JavaWeb课程体系里的核心技术来实现。JSP+Servlet+MySQL+Tomcat,这套组合本身就是JavaWeb的定义。用Spring Boot当然行,但三个风险你要想清楚:一是如果老师按题目要求检查,你做的东西可能偏离课程考核范围;二是Spring Boot封装了太多东西,你在答辩时如果被问到底层请求流程,讲不清楚反而扣分;三是这个项目本身逻辑不复杂,用Servlet完全够用,没必要引入框架增加自己写代码的负担。

从这个项目的分工来看,JSP负责视图展示,Servlet负责请求控制和转发,JavaBean和DAO负责数据操作,前端用HTML、CSS、JavaScript做页面交互。这些都是大三JavaWeb课程里反复练过的东西,做成毕设,老师一眼就能看出你确实掌握了这门课的核心内容。

2.2 分层架构与项目目录结构

目录结构上,我按标准的MVC分层来组织,同时兼顾“源码可读性”。这里我给出一个参考结构,你如果自己复刻可以直接用。

code复制src
├── com.example.filter
│   └── EncodingFilter.java
├── com.example.servlet
│   ├── UserServlet.java
│   ├── ProductServlet.java
│   ├── SkinTestServlet.java
│   ├── CommentServlet.java
│   └── AdminServlet.java
├── com.example.service
│   ├── UserService.java
│   ├── ProductService.java
│   ├── SkinTestService.java
│   └── CommentService.java
├── com.example.dao
│   ├── BaseDao.java
│   ├── UserDao.java
│   ├── ProductDao.java
│   ├── SkinTestDao.java
│   └── CommentDao.java
├── com.example.entity
│   ├── User.java
│   ├── Product.java
│   ├── Category.java
│   ├── SkinType.java
│   └── Comment.java
└── com.example.util
    ├── DBUtil.java
    └── IngredientMatcher.java
webapp
├── static
│   ├── css
│   └── js
├── WEB-INF
│   └── web.xml
├── index.jsp
├── login.jsp
├── register.jsp
├── product_list.jsp
├── product_detail.jsp
├── skin_test.jsp
└── admin
    └── product_manage.jsp

有几点经验:第一,把JSP文件放在web根目录下,访问路径比较短,调试方便;没有非要塞进WEB-INF,除非你想做严格的权限控制。第二,Servlet类不要一窝蜂写在一个类里,按用户、产品、评论等不同资源拆成多个Servlet,职责清晰,答辩时也容易讲。第三,DBUtil和BaseDao放util包,BaseDao里面封装通用增删改查方法,减少重复代码。

2.3 数据库设计:核心表结构与关联关系

数据库是这个项目的根基,表结构设计好了,后面写代码会省很多事。我这里按核心业务拆了六张表。

用户表(t_user):存储用户的账号密码、昵称、肤质类型、创建时间。密码存的是MD5加密后的值,不能明文存。

分类表(t_category):产品分类,比如护肤、彩妆、香水、个护。字段包括分类ID、分类名称。

产品表(t_product):字段包括产品ID、产品名称、品牌、分类ID、价格、功效描述、适用肤质、主要成分、图片路径、库存、产品评分。

评价表(t_comment):关联用户ID和产品ID,存评论内容、评分、评论时间。

收藏表(t_favorite):关联用户ID和产品ID,加上创建时间,这是典型的多对多关系中间表。

价格记录表(t_price):关联产品ID,存价格、记录时间和记录来源。

这几个表之间的外键逻辑我建议在Java代码里维护,不要过度依赖数据库物理外键,否则插入数据的时候总会被约束卡住。逻辑外键对毕设来说完全够用,还能避免一些级联操作的坑。

3. 核心功能模块的实现与代码解读

3.1 用户模块:注册登录与会话管理

用户模块是所有系统的基础,这个模块做的好坏直接影响到后面所有功能的演示。注册的核心逻辑是:用户名唯一性校验、密码加密存储、验证码校验。

验证码我用的是Java原生生成的图片验证码,不用第三方库,代码不复杂,也能体现基本功。登录成功后,把用户对象放进Session,同时记录一下用户ID,后面收藏、评论、测评都从这个Session里取用户信息。

为了防止中文乱码,我在Filter里统一处理了编码问题。这个Filter的代码量很小,但作用很大,属于实战里必须有的一环。

java复制@WebFilter("/*")
public class EncodingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=UTF-8");
        chain.doFilter(req, resp);
    }
}

Session的另一个作用是权限控制。用户访问收藏、评论等接口时,如果Session里没有用户信息,直接重定向到登录页。管理员访问后台也是同样的判断,但是管理员的身份用一个单独字段来标记。

3.2 肤质测评与推荐匹配:核心业务逻辑

这是这个网站区别于普通电商系统的灵魂模块。皮肤测评的设计思路是:设计一套问卷,每道题的选项对应不同肤质维度的加分。

比如问卷有三个维度:油脂分泌情况、敏感程度、水分保持情况。测试者回答5-8道题之后,系统根据得分综合判断肤质类型,可能是油性、干性、混合性、敏感性中的一种。

测评完之后,推荐匹配逻辑就可以做了。产品表里有个字段叫suitable_skin,就是“适用肤质”,值可以是“油性”、“干性”、“混合性”、“敏感性”,也可以是组合,比如“油性/混合性”。推荐时把用户肤质和产品适用肤质做匹配,匹配上的产品按评分倒序排列。

核心查询SQL大概长这样:

sql复制SELECT * FROM t_product
WHERE suitable_skin LIKE '%${skinType}%'
ORDER BY product_score DESC
LIMIT 10;

这里有个细节要注意:用LIKE做匹配虽然简单,但如果适用肤质字段写法不统一,比如一条数据是“油性、混合性”,另一条是“油性/混合性”,就会出现匹配不上。所以我在设计表结构时,用了统一的分隔符规范,同时在插入数据时做清洗。这个点我在项目里专门写了一个数据检查工具类,用来扫描全表的分隔符格式。

如果你的毕设想再提升一个档次,可以在测评后多做一步:记录用户测评结果的历史表,下次进来可以看到上次测评时间和肤质变化趋势。这个模块看起来不多,但在答辩时很有展示性。

3.3 产品展示与成分解析模块

产品列表页和详情页是一个纯展示和技术细节结合的地方。列表页除了分页展示,我还加了两个筛选维度:按分类筛选、按价格区间筛选。这里我用的是ProductServlet接收参数,拼SQL条件查询,参数直接拼SQL很危险,有SQL注入风险,所以我用了PreparedStatement,参数统一用?占位。

成分解析是我觉得比较有意思的地方。美妆产品详情页上往往有一串化学名词,普通用户根本看不懂。我在数据库里维护了一张成分词典表,把常见的烟酰胺、水杨酸、视黄醇、传明酸、玻尿酸等成分的作用说明都存进去。当用户打开产品详情页时,后台把该产品的成分字段拆分成一个个关键词,然后用成分词典表匹配,匹配到了就把说明显示在成分清单里。

java复制public static List<String> matchIngredients(String ingredients) {
    List<String> result = new ArrayList<>();
    if (ingredients == null || ingredients.isEmpty()) {
        return result;
    }
    for (String item : dictionary) {
        if (ingredients.contains(item)) {
            result.add(item);
        }
    }
    return result;
}

这个模块的技术含量不高,但业务代入感很强。你想象一下演示时的场景:用户打开一个产品详情页,看到“烟酰胺”后面跟着一行小字“具有美白提亮、控油等功效”,这比干巴巴的产品列表有说服力多了。

3.4 收藏、评论与价格比较

收藏功能是一个典型的多对多关系实现。用户和产品之间通过t_favorite表关联。我在ProductServlet里预留了一个favUser接口,登录用户点击收藏按钮,先检查是否已经收藏,没有则插入记录,有则取消收藏。收藏列表页展示的是当前用户收藏过的所有产品。

评论功能也相对简单,但要注意两个点:一是评论内容要做XSS过滤,不能直接把用户输入的