本项目探索如何利用jfinal框架来设计网上商城。项目简单但功能齐全,能够基本符合使用对象的需求,可以实现商品购买和数据管理。其中,项目用到enjoy模板引擎、控制器、validator等技术,实现了分页、文件上传、动态添加商品、用户订单等效果。
总体功能设计
管理员
管理员通过商品管理,能够查看所有的商品信息,根据信息增加库存,还能够添加商品的有关信息,设置商品的库存数量、价格、商品名称、所属种类,并完成图片的上传,这样用户就能从前台显示的页面中看到所有在售商品。管理员还可以根据需要对已经添加的商品信息进行修改和删除。
管理员通过订单管理,能够查看到用户上传的订单信息,包括商品名称、数量、收件人姓名、收件地址、电话。管理员还可以修改订单的状态,其中订单状态有未出库、已出库、已送达、未签收、已签收,在用户签收订单后,管理员可将订单信息删除。
管理员通过用户管理,能够查看所有的账号信息,包括用户名、身份、手机号,并可以根据需要添加管理员。
普通用户
没有注册的用户,可以点击“注册”,即可注册账号。用户在未登录时,能够看到当前所有出售的商品,登录后,可以选择商品进行购买,还能进入“我的订单”,查看所有订单的信息,并签收订单。
商品展示
搜索框
我的订单
环境配置
1.配置Java的基础环境和Maven的环境配置。
新建MAVEN_HOME,在它的后面加上MAVEN安装文件路径。然后在path中添加“%MAVEN_HOME%/bin”
2.创建Maven项目,添加 jfinal-undertow 与 jfinal 依赖。
打开 pom.xml 文件,在其中添加如下依赖.
<dependency>
<groupId>com.jfinal</groupId>
<artifactId>jfinal-undertow</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>com.jfinal</groupId>
<artifactId>cos</artifactId>
<version>2019.8</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.29</version>
</dependency>
<dependency>
<groupId>com.jfinal</groupId>
<artifactId>jfinal</artifactId>
<version>4.8</version>
</dependency>
3.创建项目
在项目 src/main/java 目录下创建demo包,并在 demo 包下创建 DemoConfig 文件
public class DemoConfig extends JFinalConfig {
/**
* 注意:用于启动的 main 方法可以在任意 java 类中创建,在此仅为方便演示
* 才将 main 方法放在了 DemoConfig 中
*
* 开发项目时,建议新建一个 App.java 或者 Start.java 这样的专用
* 启动入口类放置用于启动的 main 方法
*/
static Prop p;
static void loadConfig() {
if(p==null) {
p=PropKit.useFirstFound("demo-config.txt","demo-config-dev.txt");
}
}
public static DruidPlugin createDruidPlugin() {
loadConfig();
return new DruidPlugin(p.get("jdbcUrl"),p.get("user"),p.get("password").trim());
}
public static void main(String[] args) {
//设置端口号
UndertowServer.start(DemoConfig.class, 82, true);
}
public void configConstant(Constants me) {
loadConfig();
me.setDevMode(true);
}
public void configRoute(Routes me) {
//设置路由
me.add("/shopping", shoppingController.class);
}
public void configEngine(Engine me) {
//分页
me.addSharedFunction("_paginate.html");
}
public void configPlugin(Plugins me) {
//加载数据库
DruidPlugin druidPlugin=new DruidPlugin(p.get("jdbcUrl"),p.get("user"),p.get("password").trim());
me.add(druidPlugin);
ActiveRecordPlugin arp=new ActiveRecordPlugin(druidPlugin);
_MappingKit.mapping(arp);
me.add(arp);
}
public void configInterceptor(Interceptors me) {}
public void configHandler(Handlers me) {}
}
在demo 包下创建 HelloController 类文件
package demo;
import com.jfinal.core.Controller;
public class shoppingController extends Controller {
public void index() {
renderText("Hello JFinal World.");
}
}
启动项目(http://localhost:82/shopping):点击demoConfig,选择run as->java application
项目功能技术
enjoy模板引擎
利用该技术可以直接把java代码嵌入到html文件中,实现前端与后台之间的信息传递。
控制器
通过继承interceptor接口并编辑相应的方法,给特定功能设置附加条件,完善系统功能。
Validator
通过继承Validator类,可以避免用户输入空白信息,产生bad request,并能暂时保存用户上传的信息,便于修改。
分页
能够快速显示相应信息,减轻服务器存储过多数据的负担。
在网址中传入参数
通过设置跳转界面的网址,添加参数,便于系统判断相应的信息。
文件上传
设置file类的实例对象,获取文件类型并下载文件。
jfinal官网https://jfinal.com/doc
项目功能实现
1.商品显示
利用enjoy引擎中的for指令,结合for.index方法和循环结构,显示商品图片。
<table name="table" style="text-align:right;margin-top:10px" border="1px solid grey" >
<tr >
#for(x:item)
#set(i=x.id)
<td ><form type="hidden" style="height:340px;width:316px" name="i++" value="#(i)" method="post" action="buy/#(x.id)?id=#(x.id)&&user=#(request.getParameter('user'))">
<input type='image' src='img/#(i).jpg' style='margin:2px;width:300px;height:260px'/><br/>
<span style="text-align:center;padding-right:10px;">价格:#(x.price)元</span>   
<span style="text-align:center;padding-right:30px;">数量:#(x.storage)</span><br>
<input type='submit' value='立即购买' name="add" style="margin-right:30px;text-align:center;margin-top:10px;text-align:right;" >
#if((for.index)%4==3)
</form>
</td>
</tr>
<tr>
#end
#if((for.index)%4!=3)
</form>
</td>
#end
2.登录
设置方法查询该账号是否存在、密码是否正确,根据不同情况,将验证的信息存在attribute中便于长期存储信息,后台从中取出并显示出信息,有一个条件不符合,就会返回登录界面,否则根据身份跳转到对应的界面。
@Before(shopInterceptor.class)
public void userEnter() {
String u=this.getPara("username");
String p=this.getPara("pwd");
java.util.List<Login> pwd=new ArrayList<Login> ();
pwd=s.findPwd(u);
if(u!=null && p!=null)//密码或账号不为空
{if(s.findByName(u)&&pwd.size()!=0)
{
if(p.equals(pwd.get(0).getPwd()))//密码正确
{
if(pwd.get(0).getRole().equals("1"))//普通用户
{this.setAttr("login","consumer success");
this.setAttr("username", u);
this.setAttr("pwd", p);
redirect("index?user="+u);
System.out.print(this.getAttr("pwd"));
}
else if(pwd.get(0).getRole().equals("0"))//管理员
{this.setAttr("login","admin success");
render("business.html");}
}
else {this.setAttr("login","pwd fails");//密码错误
render("userEnter.html");}
}
else if(pwd.size()==0) {this.setAttr("login","username fails");//用户不存在
render("userEnter.html");}
}
else {
this.setAttr("login","null");
render("userDengLu.html");
}
}
3. 文件上传
//上传文件
public void picAdd() {
this.setAttr("clothe", s.findByIdClothe(this.getParaToInt("id")));
render("picAdd.html");
}
public void upload() {
UploadFile uploadFile=getFile();
//获取文件名
String fileName=uploadFile.getOriginalFileName();
//获取文件类型
String type=fileName.substring(fileName.lastIndexOf("."));
System.out.print(fileName);
//通过文件流读文件
File file=uploadFile.getFile();
//获取文件在项目中的存储位置
File t=new File(this.getRequest().getServletContext().getRealPath("/")
+"/shopping/img/"+this.getPara("id")+type);
//文件名重命名
file.renameTo(t);
//url重定向
redirect("goodManage/1");
}
4.设置当前日期及星期数
Calendar c=Calendar.getInstance();
int y=c.get(Calendar.YEAR);//年
int m=c.get(Calendar.MONTH)+1;//月
int r=c.get(Calendar.DATE);//日
this.setAttr("date", y+"年"+m+"月"+r+"日");
String week = c.get(c.DAY_OF_WEEK) - 1 + "";
if ("0".equals(week)) {
week = "七";
}
if ("1".equals(week)) {
week = "一";
}
if ("2".equals(week)) {
week = "二";
}
if ("3".equals(week)) {
week = "三";
}
if ("4".equals(week)) {
week = "四";
}
if ("5".equals(week)) {
week = "五";
}
if ("6".equals(week)) {
week = "六";
}
this.setAttr("week", "星期"+week);
5.分页显示用户数据
<body>
#include("page_head.txt")
<div>
<form method="post" action="useAdd">
<input type="submit" style="margin: 10px 320px 10px 0px;float:right;background-color: rgb(196, 32, 32);color:white;height:30px;width:100px" value="添加管理员"/>
</form>
<form method="post" action="selUse">
<input type="submit" style="margin: 10px 10px 10px 0px;float:right;background-color: rgb(196, 32, 32);color:white;height:30px;width:100px" value="查询"/>
</form>
</div>
<div>
<div style="padding-left:10px;padding-top:20px">
<form action="" method="post">
<table style='text-align:center;' border='1' width='80%' >
<tr>
<td>编号</td>
<td>用户名</td>
<td>身份</td>
<td>电话</td>
<td width='10%'></td>
<td width='10%'></td>
</tr>
#for(x:login)
<tr>
<td style="text-align:center;">编号:#(x.useId)</td>
<td style="text-align:center;">用户名:#(x.username)</td>
#if((x.role).equals("1"))
<td style="text-align:center;">用户</td>
#end
#if((x.role).equals("0"))
<td style="text-align:center;">管理员</td>
#end
<td style="text-align:center;">电话:#(x.phone)</td>
<td><a href="userDelete/#(x.useId)" class="link1" style="color:blue">删除</a></td>
<td><a href="userEdit/#(x.useId)" class="link1" style="color:blue;">修改</a></td>
</tr>
#end
</table>
</form>
</div>
</body>
public void useManage() {
this.setAttr("login", s.findAllLogin());
render("useManage.html");
}
public List<Login> findAllLogin(){
//查询数据库,返回系统内置方法
return l.findAll();
}
6.拦截器
public class shopV extends Validator {
@Override
protected void validate(Controller c) {
// TODO Auto-generated method stub
this.validateRequiredString("clothe.clotheName", "clotheName", "clotheName cannot be null");//是否有数值
this.validateRequiredString("clothe.price", "price", "price cannot be null");
this.validateRequiredString("clothe.storage", "storage", "storage cannot be null");
}
@Override
protected void handleError(Controller c) {
// TODO Auto-generated method stub
c.keepModel(Clothe.class);
String actionKey=this.getActionKey();
if("/shopping/saveGood".equals(actionKey))
c.render("produceAdd.html");
}
}