不要上来就写代码,要先思考,分析。
需求分析:
无颜色框是商家的功能
概要设计:分为以下几个模块,运行流程,功能分配,接口设计,数据结构,出错设计,日志设计;
运行流程(重点):
什么时候定义接口,什么时候定义父类? 定义接口是向很多层提供服务的,而父类则是在每一个项目里面,针对这个项目业务逻辑。对于所有项目的公共部分我们定义成接口,对本项目使用的模块,定义基类
txt用json格式存储,因为有现成的包可以使用,利用字符流中的字符缓冲流读写(效率高)。
IDataAccess ISysLog前的I指代interface接口,(定义接口的习惯,业务模块按业务的来,非业务的按I来)
每一个实体存储到数据库中都是一条数据,每一条数据都会有一个id(数据的唯一标识), 实际开发中,数据删除并没有实际删除,而是逻辑删除,(把它的删除状态标记为已删除,但他还存在),你在查询时,看不到这条数据,你认为删除了,但他实际还在数据库中。只有逻辑删除,才会有删除状态和删除时间。
请求主要做了两件事,客户端向服务器端发送具体的数据或者参数,调用对应的方法来执行。
开发前的准备工作:
json存储在文本文档里,他的数据类型就是字符串,所有的编程语言都支持字符串,所以json是跨编程语言的,跨平台的;
json数据表现形式只有两种,要么是一个对象,要么是一个数组。
package cn.itcast.eshop.common.util;
import cn.itcast.eshop.common.entity.Entity;
import com.alibaba.fastjson.JSON;
import java.util.ArrayList;
import java.util.List;
/**
* json工具类,
* 处理和json相关的所有内容
*/
public class JSONUtil {
/**
* 把对象转化成json格式的字符串
*
* @param entity 指定对象
* @return json格式的字符串
*/
public static String entity2JSON(Object entity) {
return JSON.toJSONString(entity);
}
public static String entitylist2JSON(List<?> entityList){
return entity2JSON(entityList);
}
/**
* 把json字符串转换成指定的对象
*
* ?泛型通配符,代表的未知任意类型,或者是Object
* @param json 要转换的对象
* @param clazz 指定的类型
* @return 返回Object对象
*/
/*public static Object JSON2Entity(String json,Class<?> clazz){
Object obj= JSON.parseObject(json,clazz);
return obj;
}*/
public static <T>T JSON2Entity(String json,Class<T> clazz){//参数传什么类型就返回什么类型,利用泛型;来做
return JSON.parseObject(json,clazz);
}
/**
* 将json数组转换成指定类型的对象列表
* @param json 数据
* @param clazz 指定的类型对象
* @param <T> 指定的类型
* @return 对象列表
*/
public static <T> List<T> JSON2List(String json,Class<T> clazz){
return JSON.parseArray(json,clazz);
}
//测试效果
public static void main(String[] args) {
Entity entity = new Entity();
entity.setId("1002");
entity.setCreateTime("11:22");
String json = entity2JSON(entity);
System.out.println(json);//{"createTime":"11:22","id":"1002","isDel":"1"}
System.out.println();
List<Entity> entitylist =new ArrayList<>();
entitylist.add(entity);
String jsonlist = entitylist2JSON(entitylist);
System.out.println(jsonlist);//[{"createTime":"11:22","id":"1002","isDel":"1"}]
System.out.println();
/*String jsonstr="{\"createTime\":\"13:55\",\"id\":\"1002\",\"isDel\":\"1\"}";
Object obj=JSON2Entity(jsonstr,Entity.class);//需要的参数是json字符串和字节码文件对象
//System.out.println(obj);这样直接输出得到的是一个地址,所以我们利用强制类型转换
Entity e=(Entity)obj;
System.out.println(e.getCreateTime());//13:55*/
String jsonstr="{\"createTime\":\"14:06\",\"id\":\"1002\",\"isDel\":\"1\"}";
Entity e=JSON2Entity(jsonstr,Entity.class);
System.out.println(e.getCreateTime());//14:06
System.out.println();
String jsonarr="[{\"createTime\":\"14:11\",\"id\":\"1002\",\"isDel\":\"1\"},{\"createTime\":\"11:22\",\"id\":\"1002\",\"isDel\":\"1\"}]";
List<Entity> el=JSON2List(jsonarr,Entity.class);
System.out.println(el.get(0).getCreateTime());//14:11
System.out.println(el.get(1).getCreateTime());//11:22
}
}
package cn.itcast.eshop.common.entity;
/*
*实体类
* 所有实体类的父类
* 职责:封装数据
*/
public class Entity {
private String id;
//数据的唯一标识
private String createTime;
//数据的创建时间
private String deleteTime;
//数据的创建时间
private String isDel="1";
//数据的删除状态,0已删除,1正常,默认1
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCreateTime() {
return createTime;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
public String getDeleteTime() {
return deleteTime;
}
public void setDeleteTime(String deleteTime) {
this.deleteTime = deleteTime;
}
public String getIsDel() {
return isDel;
}
public void setIsDel(String isDel) {
this.isDel = isDel;
}
}
package cn.itcast.eshop.common.action;
/*
*Action 控制器类的基类
* 1.封装请求数据
* 2.校验权限
* 3.调用服务层(service)处理业务逻辑
* 4.日志的记录
* 5.返回消息到客户端
*/
public class BaseAction {
}
package cn.itcast.eshop.common.service;
/*
*服务层,所有模块服务层的顶层接口
* 1.调用dao层获取数据
* 2.处理业务逻辑
* 3.把处理结果返回给action
*/
public interface BaseService {
}
package cn.itcast.eshop.common.dao;
/*
*数据访问层,所有模块数据访问层的顶层接口
* 1.获取数据
* 2.把数据返回给服务层(service)
*
*/
public interface BaseDAO {
}
package cn.itcast.eshop.common.dao;
/**
* 访问数据库(文件)
* 返回结果给DAO
*/
public interface IDataAccess {
}
package cn.itcast.eshop.client;
/**
* 客户端顶层父类
* 处理公共的用户操作
*/
public class Client {
}
userService返回处理业务的结果,返回给userAction,登录成功或者失败,由useraction控制器来决定,userAction返回的结果是一个json格式的字符串,userclient拿到数据需要对数据进行解析,将数据转换成实体类的对象
package cn.itcast.eshop.common.entity;
/**
* 消息封装类
* (因为所有模块都会用到,所以放在common里)
*
*/
public class Msg {
private String msg;//消息内容
private String type;//消息类型 成功SUCCESS,失败FAIL
/** 消息类型 成功*/
public static final String SUCCESS="SUCCESS";
/** 消息类型 失败*/
public static final String FAIL="FAIL";
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
package cn.itcast.eshop.client;
/**
* 客户端顶层父类
* 处理公共的用户操作
*/
public class Client {
/** 全局 用户操作 登录*/
public static final String LOGIN="L";
/** 全局 用户操作 上一次操作记录*/
public static final String HISTORY="I";
/** 全局 用户操作 首页*/
public static final String INDEX="I";
public static void main(String[] args) {//效果测试
Client c=new Client();
c.start();
}
public void start(){
UserClient userclient=new UserClient();
String result= userclient.showlogin();
if(result.equals(INDEX)){
//首页
System.out.println("这是首页");
}else if(result.equals(LOGIN)){
//登录页面
System.out.println("这是登录页面");
}else if (result.equals(HISTORY)){
//上一次操作页面
System.out.println("这里是历史页面");
}else{
System.out.println("出错了");
}
}
}
package cn.itcast.eshop.user.action;
import cn.itcast.eshop.common.action.BaseAction;
import cn.itcast.eshop.common.entity.Msg;
import cn.itcast.eshop.common.util.JSONUtil;
/**
* 用户控制器类
* 处理所有用户的后台操作,并返回Json格式的字符串消息
*/
public class UserAction extends BaseAction {
private String username;//用户名
private String password;//用户密码
/**
* 用户登录功能
* @return
*/
public String login(){
System.out.println("username:"+username);
System.out.println("password:"+password);
Msg msg=new Msg();
msg.setType(Msg.FAIL);//登录失败
msg.setMsg("这里是返回消息");
return JSONUtil.entity2JSON(msg);
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
package cn.itcast.eshop.client;
import java.util.Scanner;
import cn.itcast.eshop.common.entity.Msg;
import cn.itcast.eshop.common.util.JSONUtil;
import cn.itcast.eshop.user.action.UserAction;
/**
* 用户操作界面
* 所有和用户操作相关的内容,都放到这个类里
*/
public class UserClient extends Client{
/**
* 用户登录操作界面
* 1.使用控制台提示用户输入用户名,密码
* 2.向服务器发送请求,并接受返回的字符串
* 使用setter方法把数据传给Action
* 调用Action的登录功能
* 3.解析消息字符串,提示用户信息
* 4.使用字符串常量作为跳转标记
* 成功返回上一次操作的页面
* 失败返回登录页面
* @return
*/
public String showlogin(){
//1.使用控制台提示用户输入用户名,密码
Scanner sc=new Scanner(System.in);
System.out.println("请输入用户名:");
String username=sc.nextLine();
System.out.println("请输入密码:");
String password=sc.nextLine();
//2.向服务器发送请求,并接受返回的字符串
UserAction useraction=new UserAction();
//2.1使用setter方法把数据传给Action
useraction.setUsername(username);
useraction.setPassword(password);
//2.2调用Action的登录功能
String result=useraction.login();//返回一个json格式的字符串结果
//3.解析消息字符串,提示用户信息
Msg msg=JSONUtil.JSON2Entity(result, Msg.class);
if(msg.getType().equals(Msg.SUCCESS)){
//登录成功
System.out.println("登录成功!");
return HISTORY;
}else{
System.out.println("登录失败!");
return LOGIN;
}
}
}
在Client类中,构建主函数对UserClient类中的showlogin方法测试
Msg多了一个属性,(当我获取了一条数据时,我们应该怎样,返回给前台界面,必须有一个属性去携带这个数据,而他就是obj,因为这个数据可能是任意类型,可能是一个实体,一个实体列表等等,所以利用Object类型
package cn.itcast.eshop.user.service;
import cn.itcast.eshop.user.entity.User;
public interface UserService {
User login (User user) throws Exception;
}
package cn.itcast.eshop.user.service.impl;
import cn.itcast.eshop.user.entity.User;
import cn.itcast.eshop.user.service.UserService;
public class UserServiceImpl implements UserService {
@Override
public User login(User user) throws Exception {
return null;
}
}
package cn.itcast.eshop.user.entity;
import cn.itcast.eshop.common.entity.Entity;
public class Person extends Entity {
private String name;
private String sex;
private String phone;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
package cn.itcast.eshop.user.entity;
public class User extends Person{
private String username;
private String password;
private String role="NORMAL";//代表普通用户
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
package cn.itcast.eshop.user.action;
import cn.itcast.eshop.common.action.BaseAction;
import cn.itcast.eshop.common.entity.Msg;
import cn.itcast.eshop.common.util.JSONUtil;
import cn.itcast.eshop.user.entity.User;
import cn.itcast.eshop.user.service.UserService;
import cn.itcast.eshop.user.service.impl.UserServiceImpl;
/**
* 用户控制器类
* 处理所有用户的后台操作,并返回Json格式的字符串消息
*/
public class UserAction extends BaseAction {
private String username;//用户名
private String password;//用户密码
/**
* 用户登录功能
* 1.封装数据到User对象
* 2.调用UserService处理逻辑
* User Login(User user) throws Exception
* 3.异常处理
* 4.根据服务层返回结果生成消息
* 信息实体类Msg
* 5.记录日志(待开发)
* 6.响应信息到客户端
* @return
*/
public String login() {
Msg msg = new Msg();
//3.异常处理
try { //因为login方法中的每一行都可能会出错,为了避免这种情况,所以我们把异常处理放在最上面
//1.封装数据到User对象
User user = new User();
user.setUsername(username);
user.setPassword(password);
//2.调用UserService处理逻辑
// User Login(User user) throws Exception
UserService userService = new UserServiceImpl();
user=userService.login(user);//利用user接受消息
//4.根据服务层返回结果生成消息
// 信息实体类Msg
if(user!=null) {
msg.setType(Msg.SUCCESS);//登录成功
msg.setMsg("登录成功");
}else {
msg.setType(Msg.FAIL);//登录失败
msg.setMsg("用户名或密码不正确");
}
return JSONUtil.entity2JSON(msg);
}catch(Exception e){
e.printStackTrace();//如果出了异常就会打印出来
//但还是需要返回消息
//封装一个错误消息
msg.setType(Msg.FAIL);//登录失败
msg.setMsg("服务器异常");
return JSONUtil.entity2JSON(msg);
}
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
package cn.itcast.eshop.client;
/**
* 客户端顶层父类
* 处理公共的用户操作
*/
public class Client {
/** 全局 用户操作 登录*/
public static final String LOGIN="L";
/** 全局 用户操作 上一次操作记录*/
public static final String HISTORY="I";
/** 全局 用户操作 首页*/
public static final String INDEX="I";
public static void main(String[] args) {//效果测试
Client c=new Client();
c.start();
}
public void start(){
UserClient userclient=new UserClient();
String result= userclient.showlogin();
if(result.equals(INDEX)){
//首页
System.out.println("这是首页");
}else if(result.equals(LOGIN)){
//登录页面
System.out.println("这是登录页面");
}else if (result.equals(HISTORY)){
//上一次操作页面
System.out.println("这里是历史页面");
}else{
System.out.println("出错了");
}
}
}
package cn.itcast.eshop.client;
import java.util.Scanner;
import cn.itcast.eshop.common.entity.Msg;
import cn.itcast.eshop.common.util.JSONUtil;
import cn.itcast.eshop.user.action.UserAction;
/**
* 用户操作界面
* 所有和用户操作相关的内容,都放到这个类里
*/
public class UserClient extends Client{
/**
* 用户登录操作界面
* 1.使用控制台提示用户输入用户名,密码
* 2.向服务器发送请求,并接受返回的字符串
* 使用setter方法把数据传给Action
* 调用Action的登录功能
* 3.解析消息字符串,提示用户信息
* 4.使用字符串常量作为跳转标记
* 成功返回上一次操作的页面
* 失败返回登录页面
* @return
*/
public String showlogin(){
//1.使用控制台提示用户输入用户名,密码
Scanner sc=new Scanner(System.in);
System.out.println("请输入用户名:");
String username=sc.nextLine();
System.out.println("请输入密码:");
String password=sc.nextLine();
//2.向服务器发送请求,并接受返回的字符串
UserAction useraction=new UserAction();
//2.1使用setter方法把数据传给Action
useraction.setUsername(username);
useraction.setPassword(password);
//2.2调用Action的登录功能
String result=useraction.login();//返回一个json格式的字符串结果
//3.解析消息字符串,提示用户信息
Msg msg=JSONUtil.JSON2Entity(result, Msg.class);
if(msg.getType().equals(Msg.SUCCESS)){
//登录成功
System.out.println(msg.getMsg());
return HISTORY;
}else{
System.out.println(msg.getMsg());
return LOGIN;
}
}
}
package cn.itcast.eshop.user.dao;
import cn.itcast.eshop.common.dao.BaseDAO;
import cn.itcast.eshop.user.entity.User;
import java.util.List;
public interface UserDAO extends BaseDAO {
List<User> getEntityLIst() throws Exception;
}
package cn.itcast.eshop.user.dao.impl;
import cn.itcast.eshop.user.dao.UserDAO;
import cn.itcast.eshop.user.entity.User;
import java.util.List;
public class UserDAOImpl implements UserDAO {
@Override
public List<User> getEntityLIst() throws Exception {
return null;
}
}
package cn.itcast.eshop.user.service;
import cn.itcast.eshop.user.entity.User;
public interface UserService {
User login (User user) throws Exception;
}
package cn.itcast.eshop.user.service.impl;
import cn.itcast.eshop.user.dao.UserDAO;
import cn.itcast.eshop.user.dao.impl.UserDAOImpl;
import cn.itcast.eshop.user.entity.User;
import cn.itcast.eshop.user.service.UserService;
import java.util.List;
public class UserServiceImpl implements UserService {
/**
* 用户登录,根据用户名,密码获取用户对象
* 1.调用UserDAO获取用户列表数据
* List<User> getEntityLIst() throws Exception;
* 2.遍历用户列表,逐个与给定用户对象的用户名,密码进行匹配
* 3.匹配成功则返回该用户对象,失败返回null
* @param user 封装了用户名 密码的实体对象
* @return 返回user对象,或者当用户名 密码错误时返回null
* @throws Exception
*/
private UserDAO userDAO;//以属性的方式写出来,就不用申明了
@Override
public User login(User user) throws Exception {
//1.调用UserDAO获取用户列表数据
userDAO=new UserDAOImpl();
List<User> userlist=userDAO.getEntityLIst();
//2.遍历用户列表,逐个与给定用户对象的用户名,密码进行匹配
if(userlist!=null){//首先判断列表是否存在
for (User u : userlist) {
if(u.getUsername().equals(user.getUsername())&&
u.getPassword().equals(user.getPassword()))
//与userlist中存储的用户名 密码相同
{
return u;//3.匹配成功则返回该用户对象
}
}
}
return null;//失败返回null
}
}
日志管理
根据日志级别定义方法,把对应的内容传递给方法就可以了,也不需要返回值,要么把内容打印到控制台,要么把数据打印到文件里
package cn.itcast.eshop.log.dao;
public interface ISysLog {
/** 日志级别 普通信息*/
public static final String INFO="INFO";
/** 日志级别 警告信息*/
public static final String WARN="WARN";
/** 日志级别 错误信息*/
public static final String ERROR="ERROR";
void info(String msg);
void warn(String msg);
void error(String msg);
}
package cn.itcast.eshop.log.dao.impl;
import cn.itcast.eshop.log.dao.ISysLog;
import cn.itcast.eshop.log.entity.Log;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 日志实现类
* 在控制台打印日志信息
* <p>
* 步骤:
* 1.封装日志对象
* 2.打印日志数据到控制台
*/
public class ConsoleLog implements ISysLog {
SimpleDateFormat sdf = new SimpleDateFormat("h:mm a");//创建一个简单的日期 里面的参数时要格式化的方式 得到的效果是12:08 PM
@Override
public void info(String msg) {
//1.封装日志对象
String log = new Log(msg, INFO, sdf.format(new Date())).toString();//把时间转化成string类型)
//通过重写的tostring方法来展示日志的格式
System.out.println(log);
}
@Override
public void warn(String msg) {
//1.封装日志对象
String log = new Log(msg, WARN, sdf.format(new Date())).toString();//把时间转化成string类型)
//通过重写的tostring方法来展示日志的格式
System.out.println(log);
}
@Override
public void error(String msg) {
//1.封装日志对象
String log = new Log(msg, ERROR, sdf.format(new Date())).toString();//把时间转化成string类型)
//通过重写的tostring方法来展示日志的格式
System.out.println(log);
}
//在action测试日志功能 UserAction
}
package cn.itcast.eshop.log.entity;
public class Log {
//日志内容
private String msg;
//日志级别
private String level;
//日志发生时间
private String time;
public Log() {
}
public Log(String msg, String level, String time) {
/**
* 构造方法封装日志数据
*
* @param msg 日志内容
* @param level 日志级别
* @param time 日志发生时间
*/
this.msg = msg;
this.level = level;
this.time = time;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getLevel() {
return level;
}
public void setLevel(String level) {
this.level = level;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
@Override
public String toString() {
return "["+time+"]"+level+": "+msg;
}
}
商品管理:
购物车管理
部分代码省略,直接给出最后的附有注释的项目源码
下载链接