不要上来就写代码,要先思考,分析。
需求分析: 无颜色框是商家的功能
概要设计:分为以下几个模块,运行流程,功能分配,接口设计,数据结构,出错设计,日志设计; 运行流程(重点): 什么时候定义接口,什么时候定义父类? 定义接口是向很多层提供服务的,而父类则是在每一个项目里面,针对这个项目业务逻辑。对于所有项目的公共部分我们定义成接口,对本项目使用的模块,定义基类
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; } }商品管理:
购物车管理 部分代码省略,直接给出最后的附有注释的项目源码 下载链接