到山东找蓝翔的资源

  • 基于Java实现的图书管理系统

    1.项目简介1.1课设背景该图书管理系统应用于中小学生的图书馆中,面向的客户主要是中小学生和教师,在用户进行图书的相关业务时,该系统能够合理有效的去管理。
    通过分析可以发现,在市面上的图书管理系统基本上可以分为两类:一类是由各大高校、研究院所和大型图书馆共同开发的大型图书管理系统。大型图书管理系统的优点是设计先进、功能强大,缺点是价格昂贵、维护困难、操作复杂。因此,这类系统只在大型图书馆中适用,而对于只有一两名管理员、而且管理员的计算机素质普遍不高的普通中小学来说,则不太适用。另一类则是小型软件。此类软件只具备图书管理的基本功能,其人机交互界面普遍较差,功能较弱,软件的使用效果不太理想。根据这种情况,我们设计开发了一套适用于普通中小学校图书馆的图书管理系统。
    1.2系统架构选型方案一 B/S架构
    优点:
    ①可以很方便的使用
    ②升级维护的成本小
    ③不依赖于固定的开发工具、操作系统等固话软件,兼容性更强
    方案二 C/S架构
    优点:
    ①拥有高性能,响应速度更快
    ②面向相对固定的用户群,对信息安全的控制能力更强
    ③有较强的事务处理能力,能实现复杂的业务流程
    通过以上两种架构的对比,并分析用户的需求,因为本图书管理系统需要进行实时交互、对反应速度要求较高,而且中小学中针对的人群比较固定,所以不需要建立在广域网上增加安全风险。综上所述,本系统最终选型C/S模式
    1.3功能分析图书流通操作根据图书的实际流向,分别进行图书借阅、图书归还、图书预约等操作,并形成相应的记录,包括读者编号、图书编号、借阅时间、应还时间、归还时间、预约时间等信息,借书还书与预约都要经过工作人员的审核,如果图书有损坏等问题可以记录违章记录,工作人员可以采购图书入库。
    查询功能工作人员与读者都可以对图书信息进行灵活的查询操作。
    工作人员可以查询读者的相关信息,包括读者卡信息和读者的相关借还操作,除此之外,读者还可以查询自己的个人信息和相关借阅操作,包括当前借阅图书、借阅历史、归还图书、违章记录等信息。
    设置功能超级管理员、工作人员、读者都可以修改自己的密码,而超级管理员可以去修改工作人员和读者的密码。超级管理员可以添加工作人员与读者,还可以注销读者卡。
    1.4系统用例图1.4.1读者用例图
    读者所包含的用例有:
    (1)登录系统(Login):可以通过登录系统进入读者系统的主界面
    (2)借书(Borrow books):进行借书的业务
    (3)还书(Return books):可以进行还书业务
    (4)预约借书(Reserve books):对别人已经借走的书籍可以进行预约借书
    (5)查询图书:可以查询所有的书籍,并且可以通过关键字信息对书籍进行查询
    (6)查询个人信息:可以查看读者自己的信息
    (7)查询当前借阅:可以查询该读者当前已借书籍
    (8)查询历史借阅:当借书并还书后,会生成历史借阅信息,读者可以查询历史借阅
    (9)查询预约信息:查询个人预约信息
    (10)违规记录:可以查询到个人是否有违规
    (11)修改密码:读者可以修改自己账号的密码
    热门推荐:会根据借书的种类与数量进行推荐
    1.4.2工作人员用例图
    工作人员所包含的用例有:
    (1)登录系统(Login):可以通过登录系统进入工作人员系统的主界面
    (2)读者管理(Reader Management):读者管理用例中包括了对读者卡信息的查询和对读者借阅、预约等操作的信息查询
    (3)读者信息查询(Query Reader’s Info):可以查询读者卡的信息
    (4)读者操作信息查询(Query Reader’s Info):可以查询读者借阅、历史借阅、违章记录等操作信息
    (5)图书管理(Book Management):图书管理用例中包含了查询图书、添加图书、修改图书用例
    (6)查询图书(Query books):可以查询所有的书籍,并且可以通过关键字信息对书籍进行查询,还可以进行删除
    (7)添加图书(Add books):输入图书信息将图书入库
    (8)修改图书(Update books):输入图书号查询然后可以对相关信息进行修改
    (9)借阅管理(Borrow Management):借阅管理用例包含了审核借阅、违章记录、审核预约
    (10)审核借阅(Verify Borrow):可以对读者借书申请进行审核
    (11)审核预约(Verify Reserve):可以对读者预约申请进行审核
    (12)违规记录(Query Uncomply):可以查询该读者的违章记录
    1.4.3超级管理员用例图
    超级管理员所包含的用例有:
    (1)登录系统(Login):可以通过登录系统进入工作人员系统的主界面
    (2)添加读者(Add Reader):输入读者信息添加读者
    (3)添加工作人员(Add Worker):输入工作人员信息添加读者
    (4)查询读者信息(Query Reader):通过读者卡号查询读者信息
    (5)查询工作人员信息(Query Reader):通过工作人员卡号查询工作人员信息
    (6)注销借阅证(Delete Reader):通过读者卡号进行注销
    (7)修改读者密码(Update RPwd):可以修改读者的密码
    (8)修改工作人员密码(Update WPwd):可以修改工作人员的密码
    (9)修改密码(UpdatePwd):可以修改自己的密码
    1.5核心业务借阅功能
    读者可以在超级管理员处进行注册获得读者卡,读者卡有账号和密码信息
    1.读者输入自己的读者卡账号密码,选择读者身份,正确后即可进入读者主界面
    2.读者可以在图书查询中查看所有的图书信息,也可以通过相关信息查询某一本书。选中图书进行借阅,如果图书状态为已借出则弹出错误提示,如果为可借状态则弹出借阅信息窗口
    3.在借阅信息窗口中输入还书时间,还书日期不得早于借书日期否则会报错。提交借阅信息后修改图书状态并等待工作人员的审核
    4.工作人员审核通过之后将该借阅信息放入该读者的当前借阅信息中,在还书子界面也可以看到当前借阅的书籍。工作人员也可以给该次借阅添加违规使用信息。
    至此,完成一次借阅业务
    还书功能
    1.读者输入自己的读者卡账号密码,选择读者身份,正确后即可进入读者主界面
    2.读者可以在还书子界面中进行还书业务。还书子界面中可以看到自己当前正在借阅的书籍,选中书籍可以进行归还,接着弹出还书确认框,点击确认后会将还书信息传给工作人员,需要工作人员的审核
    3.待工作人员进行审核后,则将这次还书信息写入还书表中。工作人员还可以对这次还书业务添加违约信息
    4.至此,完成一次还书业务。当完成还书后,读者还可以查看自己的借阅历史,即一次完整的借书还书业务信息
    预约功能
    1.读者输入自己的读者卡账号密码,选择读者身份,正确后即可进入读者主界面
    2.读者可以在图书查询中查看所有的图书信息,也可以通过相关信息查询某一本书。选中图书进行预约,如果该书状态为可借则弹出错误提示,如果状态为已借出则可以预约,弹出预约信息窗口
    3.在预约信息窗口中输入预约到书时间(预约到书时间即是期望预约领书的最晚日期),预约到书日期不得早于预约开始日期否则会报错。提交预约信息后等待工作人员的审核。此时读者可以查看自己的预约信息,可以看到预约状态为等待处理
    4.工作人员可以对这次预约信息进行查询确认是否可借,如图书馆无该书则不可借,如果有书则可以推送通知。推送通知后,更新预约状态为可以借阅,读者可以查看自己的预约状态,进行图书借阅,输入相关信息完成预约借阅
    5.至此,完成一次预约业务
    2.数据结构设计2.1ER图图书与图书种类实体


    读者实体

    工作人员实体

    超级管理员实体

    图书流通的实体联系图

    2.2数据库关系模式设计根据前面所作出的图书管理系统需求,分析出系统开发时所需的表及其字段。系统主要的表有九张:读者卡表(Reader)、超级管理员表(SuperManager)、工作人员表(Worker)、图书表(Book)、图书分类表(Tkind)、借阅表(Nborrowing)、预约表(Qreserve)、归还表(Hreturn)、违规表(Uncomply)分别对应着实体图与图书流通联系图,关系模式如下:
    读者卡(读者卡号,读者卡密码,读者姓名,读者性别,读者单位,注册日期,在借数量,最多再借数量,读者卡状态)
    工作人员(工作证号,工作人员密码,工作人员姓名,工作人员性别,职务,入职日期)
    超级管理员(超级管理员账号,超级管理员密码)
    图书(书号,书名,作者,图书类型号,价格,入库时间,出版社,摘要,被借次数,图书状态)
    图书种类(图书类型号,图书类型名)
    借阅(书号,读者卡号,借书时间,应还时间,借书状态)
    归还(书号,读者卡号,借书时间,归还时间)
    预约(书号,读者卡号,预约开始时间,预约到书时间,预约状态)
    违规(违规记录号,违规理由,书号,读者卡号,借书时间,归还时间)
    2.3数据库详细设计说明为了更好的实施数据库,给出每个关系的详细说明:



    表名
    内容




    BOOK
    图书


    TKIND
    图书种类


    READER
    读者卡


    WORKER
    工作人员


    SUPERMANAGER
    超级管理员


    NBORROWING
    借阅


    HRETURN
    归还


    QRESERVE
    预约


    UNCOMPLY
    违规



    BOOK图书表



    字段名
    数据类型及长度
    大小
    字段中文名
    约束




    BID
    VARCHAR2
    15
    书号
    Primary Key


    BNAME
    VARCHAR2
    75
    书名
    Not Null


    BAUTHOR
    VARCHAR2
    100
    作者
    Not Null


    BKIND
    VARCHAR2
    15
    图书类型号



    BPRICE
    NUMBER
    10
    价格
    Not Null


    BDATE
    DATE
    7
    入库日期
    Not Null


    BPRESS
    VARCHAR2
    50
    出版社
    Not Null


    BSUMMARY
    VARCHAR2
    2000
    摘要
    Not Null


    BCNT
    NUMBER
    11
    被借次数



    BSTATUS
    NUMBER
    4
    图书状态



    READERS读者表



    字段名
    数据类型及长度
    大小
    字段中文名
    约束




    RID
    VARCHAR2
    11
    读者卡号
    Primary Key


    RPASSWD
    VARCHAR2
    100
    读者卡密码
    Not Null


    RNAME
    VARCHAR2
    100
    读者姓名
    Not Null


    RSEX
    VARCHAR2
    10
    读者性别



    RUNIT
    VARCHAR2
    100
    读者单位
    Not Null


    RDATE
    DATE
    7
    注册日期
    Not Null


    RNUM
    NUMBER
    10
    在借数量



    RTOTAL
    NUMBER
    6
    最多再借



    RSTATE
    NUMBER
    4
    读者卡状态



    WORKERS工作人员表



    字段名
    数据类型及长度
    大小
    字段中文名
    约束




    WID
    VARCHAR2
    100
    工作证号
    Primary Key


    WPASSWD
    VARCHAR2
    100
    工作人员密码
    Not Null


    WNAME
    VARCHAR2
    200
    工作人员姓名
    Not Null


    WSEX
    VARCHAR2
    10
    工作人员性别



    WDATE
    DATE
    7
    入职日期
    Not Null


    WUNIT
    VARCHAR2
    100
    职务
    Not Null



    SUPERMANAGER超级管理员表



    字段名
    数据类型及长度
    大小
    字段中文名
    约束




    SID
    VARCHAR2
    50
    超级管理员账号
    Primary Key


    SPASSWD
    VARCHAR2
    05
    超级管理员密码
    Not Null



    TKIND图书分类表



    字段名
    数据类型及长度
    大小
    字段中文名
    约束




    TID
    VARCHAR2
    15
    图书类型号
    Primary Key


    TNAME
    VARCHAR2
    100
    图书类型名
    Not Null



    NBORROWING借阅表



    字段名
    数据类型及长度
    大小
    字段中文名
    约束




    NBID
    VARCHAR2
    15
    书号
    Primary Key


    NRID
    VARCHAR2
    11
    读者卡号



    NBTIME
    DATE
    7
    借书时间



    NBRTIME
    DATE
    7
    应还时间



    NSTATE
    NUMBER
    4
    借书状态



    HRETURN归还表



    字段名
    数据类型及长度
    大小
    字段中文名
    约束




    HBID
    VARCHAR2
    15
    书号
    Primary Key


    HRID
    VARCHAR2
    11
    读者卡号



    HBTIME
    DATE
    7
    借书时间



    HBRTIME
    DATE
    7
    归还时间



    QRESERVE违约表



    字段名
    数据类型及长度
    大小
    字段中文名
    约束




    QBID
    VARCHAR2
    15
    书号
    Primary Key


    QRID
    VARCHAR2
    11
    读者卡号



    QSDATE
    DATE
    7
    预约开始时间



    QEDATE
    DATE
    7
    预约到书时间



    QSTATE
    NUMBER
    4
    预约状态



    UNCOMPLY预约表



    字段名
    数据类型及长度
    大小
    字段中文名
    约束




    UUID
    NUMBER
    11
    违规记录号
    Primary Key


    UREASON
    VARCHAR2
    200
    违规原因
    Not Null


    UBID
    VARCHAR2
    15
    书号
    Not Null


    URID
    VARCHAR2
    11
    读者卡号
    Not Null


    USDATE
    DATE
    7
    借书时间
    Not Null


    UEDATE
    DATE
    7
    归还时间
    Not Null



    3.项目实现3.1数据库配置driverClassName=oracle.jdbc.OracleDriverurl=jdbc:oracle:thin:@139.196.111.197:1521:ORCLusername=ethanpassword=oracleinitialSize=5maxActive=10maxWait=3000
    3.2连接数据库/** * Druid 连接池的工具类 */public class JDBCUtils { //1、定义一个成员变量 DataSource private static DataSource ds; static { try { //2、加载配置文件 Properties pro = new Properties(); pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("config/druid.properties")); //3、获取DataSource ds = DruidDataSourceFactory.createDataSource(pro); } catch (Exception e) { e.printStackTrace(); } } /** * 从连接池中获取连接对象 * * @return * @throws SQLException */ public static Connection getConnection() throws SQLException { return ds.getConnection(); } /** * 获取连接池对象 * * @return */ public static DataSource getDataSource() { return ds; }
    3.3登陆实现/** * 清空登录界面中表单的内容 */ public void clearContent() { //清空一些登录消息 loginMsg.setText("登录信息失效,请重新登录!"); //同时清空用户的密码 userPwd.setText(""); //idGroup.selectToggle(superAdmin); } @FXML public void exitBtnClick() { System.exit(0); } /** * 登录按钮 * @throws SQLException */ @FXML public void loginBtnClick() throws SQLException { //去除首尾空字符 String Id = userID.getText().trim(), pwd = userPwd.getText(); if(Id.isEmpty()) { loginMsg.setText("用户名不能为空!"); System.out.println("用户名不能为空!"); return; } if(pwd.isEmpty()) { loginMsg.setText("密码不能为空!"); System.out.println("密码不能为空!"); return; } //单独判断读者 if(reader.isSelected()) { String strRegex = "^[\\d]{11}$"; // 11位纯数字 boolean isNumId = Id.matches(strRegex); if (!isNumId) { loginMsg.setText("用户名格式有误,请重新输入11位有效数字!"); return; } } //单选按钮的判断 int flag = 0; String PwdName = null; String sql = null; if(idGroup.getSelectedToggle() == superAdmin) { flag = 1; PwdName = "SPasswd"; //sql = "SELECT * FROM supermanager WHERE Sid = ?"; } else if(idGroup.getSelectedToggle() == reader) { flag = 2; PwdName = "RPasswd"; //sql = "SELECT * FROM readers WHERE RId = ?"; }else { flag = 3; PwdName = "WPasswd"; //sql = "SELECT * FROM workers WHERE WId = ?"; } String[] str = ProcUtils.queryById_proc(flag,Id); if(str.length == 0) { loginMsg.setText("用户名不存在!"); System.out.println("查询不到数据!"); } else { String NowPasswd = str[1]; System.out.println("密码:" + NowPasswd); if(!NowPasswd.equals(pwd)) { loginMsg.setText("密码错误!"); System.out.println("密码错误!"); } else { Stage stage = (Stage) anChorPane.getScene().getWindow(); if(flag == 1) { //超管 stage.setTitle("超管页面"); stage.setScene(Main.saScene); Main.sac.initData(); } else if(flag == 2) { //读者 int rStatus = Integer.valueOf(str[2]); if(rStatus == 2) { loginMsg.setText("当前账号已被注销,请联系超管~"); return; } System.out.println("准备进入读者界面!"); stage.setTitle("读者页面"); stage.setScene(Main.rcScene); //设置隐藏属性的值 Main.rc.InitData(Id, str[3], rStatus == 1 ? "挂失" : "正常"); loginMsg.setText("登录成功~"); } else { //工作人员 stage.setTitle("工作人员页面"); stage.setScene(Main.wcScene); Main.wc.initData(Id, str[3]); } } } //JDBCUtils.close(rs, null, null); }
    3.4业务代码?)"; //queryList.add("%" + text + "%"); flag = 5; } else { System.out.println("这是模糊查询~");// sql = "SELECT * FROM book, tkind WHERE book.BKind = tkind.TId AND (BId = ? OR BName like ? OR BPress like ? OR BAuthor like ? OR BKind in (SELECT TId FROM tkind WHERE TName like ?))";// queryList.add(text);// queryList.add("%" + text + "%");// queryList.add("%" + text + "%");// queryList.add("%" + text + "%");// queryList.add("%" + text + "%"); flag = 6; } //setData(sql, queryList); setData(bookDao.queryBookByLike(flag, text)); } //填充表单数据 private void setData(List<model.Book> bookList) {// System.out.println(bookList);// System.out.println(bookList.get(0)); data.clear(); for (int i = 0; i < bookList.size(); ++i) { data.add(new EmpBookLook(bookList.get(i))); System.out.println(bookList.get(i)); } bookLook.setItems(data); bookIdLook.setCellValueFactory(new PropertyValueFactory<>("BId")); bookNameLook.setCellValueFactory(new PropertyValueFactory<>("BName")); bookAuthorLook.setCellValueFactory(new PropertyValueFactory<>("BAuthor")); bookPressLook.setCellValueFactory(new PropertyValueFactory<>("BPress")); bookPriceLook.setCellValueFactory(new PropertyValueFactory<>("BPrice")); bookSummaryLook.setCellValueFactory(new PropertyValueFactory<>("BSummary")); bookStatusLook.setCellValueFactory(new PropertyValueFactory<>("BStatus")); } //通过sql填充表单数据 private void setData(String sql, List<Object> code) { List<Book> bookList = template.query(sql, new BeanPropertyRowMapper<Book>(Book.class), code.toArray()); data.clear(); for(int i = 0; i < bookList.size(); ++i) { data.add(new EmpBookLook(bookList.get(i))); } bookLook.setItems(data); bookIdLook.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("BId")); bookNameLook.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("BName")); bookAuthorLook.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("BAuthor")); bookPressLook.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("BPress")); bookPriceLook.setCellValueFactory(new PropertyValueFactory<EmpBookLook, Double>("BPrice")); bookSummaryLook.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("BSummary")); bookStatusLook.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("BStatus")); }// private void setData(String sql, List<Object> code) {// List<Book> bookList = template.query(sql, new BeanPropertyRowMapper<Book>(Book.class), code.toArray());//// data.clear();// for(int i = 0; i < bookList.size(); ++i) {// data.add(new EmpBookLook(bookList.get(i)));// }// bookLook.setItems(data);// bookIdLook.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("BId"));// bookNameLook.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("BName"));// bookAuthorLook.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("BAuthor"));// bookPressLook.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("BPress"));// bookPriceLook.setCellValueFactory(new PropertyValueFactory<EmpBookLook, Double>("BPrice"));// bookSummaryLook.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("BSummary"));// bookStatusLook.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("BStatus"));// } //选择查询条件 @FXML public void M11Click() { MBbtn.setText("任意词"); } @FXML public void M1Click() { MBbtn.setText("书号"); } @FXML public void M2Click() { MBbtn.setText("书名"); } @FXML public void M3Click() { MBbtn.setText("出版社"); } @FXML public void M4Click() { MBbtn.setText("作者"); } @FXML public void M44Click() { MBbtn.setText("分类名"); System.out.println("选择分类名作为查询条件!"); } //详细界面 @FXML public void bookDetailClick() { EmpBookLook bookDetail = bookLook.getSelectionModel().getSelectedItem(); System.out.println(bookDetail); try { FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/common/bookDetail.fxml")); Parent parent = loader.load(); BookDetailController bc = loader.getController(); //填充数据 一个有纯白背景和平台装饰的舞台 Stage stage = new Stage(StageStyle.DECORATED); Stage faStage = (Stage) stackPane.getScene().getWindow(); stage.setTitle("图书详情"); stage.setScene(new Scene(parent, Main.sonWidth, Main.sonHeight)); stage.setResizable(false); //注意要设置模态窗口 stage.initModality(Modality.APPLICATION_MODAL); bc.initDetail(bookDetail); stage.initOwner(faStage); stage.show(); } catch (IOException e) { e.printStackTrace(); } } //点击借阅按钮,响应借阅事件 @FXML public void toBorrowClick() { if (Main.rc.rStatus.getText().equals("挂失")) { alert.setHeaderText("ERROR"); alert.setAlertType(Alert.AlertType.ERROR); alert.setContentText("当前借阅证为挂失状态,请联系工作人员重新办理借阅证~"); alert.show(); return; } //先去查询是否还能借出,最多200本 int rTotal = ProcUtils.queryIsBorrowByRId(accountId.getText()); //注意大浮点数要转化为整形 //不能再书籍了 if (rTotal == 0) { alert.setAlertType(Alert.AlertType.ERROR); alert.setHeaderText("ERROR"); alert.setContentText("当前借阅已达到最大可借数量:200本,不能再借阅~"); alert.show(); return; } EmpBookLook bookItem = bookLook.getSelectionModel().getSelectedItem(); alert.setAlertType(Alert.AlertType.ERROR); alert.setHeaderText("ERROR"); alert.setContentText("《" + bookItem.getBName() + "》已被借出,不能借阅~"); if (bookItem.getBStatus().equals("已借出")) { alert.show(); return; } try { FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/reader/checkout.fxml")); Parent parent = loader.load(); CheckOutController coc = loader.getController(); Stage stage = new Stage(StageStyle.DECORATED); stage.setTitle("借阅信息"); stage.setScene(new Scene(parent, Main.sonWidth, Main.sonHeight)); stage.setResizable(false); Stage stageF = (Stage) librarySearchPane.getScene().getWindow(); //通过数据库查询来设置借阅和归还信息,设置模态 stage.initOwner(stageF); stage.initModality(Modality.APPLICATION_MODAL); stage.show(); // 填充数据,查询数据库 String rId = Main.rc.getReaderId(); System.out.println(rId); //初始化数据 coc.initData(accountId.getText(), bookItem.getBId(), LocalDate.now().toString(), 1); } catch (IOException e) { e.printStackTrace(); } } public void initChartData() { //初始化图表 bookPopularChart = new PieChart(getPopularBookGraphStatistics()); bookPopularChart.setTitle("前20本书籍热门借阅排行榜"); returnStackPane.getChildren().clear(); returnStackPane.getChildren().add(bookPopularChart); } public ObservableList<PieChart.Data> getPopularBookGraphStatistics() { ObservableList<PieChart.Data> dataChart = FXCollections.observableArrayList(); String que = "SELECT * FROM book WHERE BCnt > 0 ORDER BY BCnt DESC"; List<Map<String, Object>> popularBooks = template.queryForList(que); int totBorrowCnt = 0; for (int i = 0, len = popularBooks.size(); i < len; ++i) { totBorrowCnt += Integer.parseInt(popularBooks.get(i).get("BCnt").toString()); } for (int i = 0, len = popularBooks.size(); i < len; ++i) { //最多显示20本热门书籍 if (i >= 20) break; String bpName = (String) popularBooks.get(i).get("BName"); int bpCnt = Integer.parseInt(popularBooks.get(i).get("BCnt").toString()); dataChart.add(new PieChart.Data(bpName + "(" + Math.round(1.0 * bpCnt / totBorrowCnt * 100) + "%)", bpCnt)); } return dataChart; } //初始化归还书籍的表格数据 public void initReturnData(String readerId) { List<Book> bookBorrowList = ProcUtils.initData(readerId); data.clear(); for (int i = 0; i < bookBorrowList.size(); ++i) { data.add(new EmpBookLook(bookBorrowList.get(i))); } needToReturn.setItems(data); retBookId.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("BId")); retBookName.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("BName")); retBookAuthor.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("BAuthor")); retBookStart.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("NBTime")); retBookEnd.setCellValueFactory(new PropertyValueFactory<EmpBookLook, String>("NBRTime")); } @FXML public void returnBookClick() { System.out.println("点击归还书籍"); if (Main.rc.rStatus.getText().equals("挂失")) { alert.setHeaderText("ERROR"); alert.setAlertType(Alert.AlertType.ERROR); alert.setContentText("当前借阅证为挂失状态,请联系工作人员重新办理借阅证~"); alert.show(); return; } EmpBookLook bookLook1 = needToReturn.getSelectionModel().getSelectedItem(); alert.setAlertType(Alert.AlertType.INFORMATION); alert.setHeaderText("INFORMATION"); alert.setContentText("您确定归还《" + bookLook1.getBName() + "》这本书吗?"); Optional<ButtonType> buttonType = alert.showAndWait(); //String sql = "UPDATE nborrowing SET NState = 2 WHERE NState = 1 AND NBId = ? AND NRId = ?"; if (buttonType.isPresent() && buttonType.get() == ButtonType.OK) { System.out.println("点击确定"); // 需要更新正在借阅表,等待工作人员的审核, 条件是书号+读者,1表示正在借阅 int update = ProcUtils.updateBorrowByBRId(bookLook1.getBId(), accountId.getText()); //int update = template.update(sql, bookLook1.getBId(), accountId.getText()); if (update > 0) { System.out.println("更新成功!"); //弹窗显示等待管理员处理 alert.setContentText("请等待图书馆工作人员的审核!"); alert.show(); data.remove(bookLook1); } else { System.out.println("更新失败!"); } } else { //不做任何处理 System.out.println("点击×"); } } @FXML public void reserveClick() { System.out.println("点击预约功能"); //弹出一个界面显示 String sql = ""; if (Main.rc.rStatus.getText().equals("挂失")) { alert.setHeaderText("ERROR"); alert.setAlertType(Alert.AlertType.ERROR); alert.setContentText("当前借阅证为挂失状态,请联系工作人员重新办理借阅证~"); alert.show(); return; } EmpBookLook bookItem = bookLook.getSelectionModel().getSelectedItem(); if (bookItem.getBStatus().equals("可借")) { alert.setAlertType(Alert.AlertType.ERROR); alert.setHeaderText("ERROR"); alert.setContentText("《" + bookItem.getBName() + "》可以直接借阅,请右键点击借阅该书籍~"); alert.show(); return; } //唯一标识:读者id+书籍id int aLong1 = queryForQreserveRepeat(bookItem.getBId(), accountId.getText()); if (aLong1 > 0) { System.out.println("重复预约《" + bookItem.getBName() + "》"); alert.setAlertType(Alert.AlertType.ERROR); alert.setHeaderText("ERROR"); alert.setContentText("重复预约《" + bookItem.getBName() + "》"); alert.show(); return; } else { System.out.println("可以预约"); } //有借阅也不能预约 int aLong2 = ProcUtils.queryISReservation(bookItem.getBId(), accountId.getText()); if (aLong2 > 0) { System.out.println("预约失败,《" + bookItem.getBName() + "》正在被您借阅中"); alert.setAlertType(Alert.AlertType.ERROR); alert.setHeaderText("ERROR"); alert.setContentText("预约失败,《" + bookItem.getBName() + "》正在被您借阅中"); alert.show(); return; } else { System.out.println("可以预约"); } try { FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/reader/reserveCheck.fxml")); Parent parent = loader.load(); ReserveCheckController rcc = loader.getController(); Stage stage = new Stage(StageStyle.DECORATED); stage.setTitle("预约信息"); stage.setScene(new Scene(parent, Main.sonWidth, Main.sonHeight)); stage.setResizable(false); Stage stageF = (Stage) librarySearchPane.getScene().getWindow(); //通过数据库查询来设置借阅和归还信息,设置模态 stage.initOwner(stageF); stage.initModality(Modality.APPLICATION_MODAL); stage.show(); // 填充数据,查询数据库 String rId = Main.rc.getReaderId(); System.out.println(rId); //初始化数据 rcc.initData(accountId.getText(), bookItem.getBId(), LocalDate.now().toString()); } catch (IOException e) { e.printStackTrace(); } } // 先去查询一下是否有预约该书籍,有预约则不能重复预约 public Integer queryForQreserveRepeat(String qbid, String qrid) { Connection conn = null; CallableStatement call = null; int res = 0; try { //1、获取数据库连接 conn = JDBCUtils.getConnection(); //2、定义调用存储函数的sql语句: {?= call <procedure-name>[(<arg1>,<arg2>, ...)]} String sql = "{?=call PACK_BOOKMS.queryForQervRepeat_func(?,?)}"; //3、获取执行sql对象 call = conn.prepareCall(sql); //4、对于OUT参数(返回值),需要申明为输出参数类型 call.registerOutParameter(1, OracleTypes.NUMBER); //5、对于IN参数,需要赋值 call.setString(2, qbid); call.setString(3, qrid); //6、执行调用 call.execute(); //7、取出影响的数量 res = call.getInt(1); System.out.println("是否重复预约:" + res); } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(null, call, conn); } return res; }
    4.项目展示登录功能
    有三种角色:超级管理员、工作人员、读者分别可以进行登录,还可以退出界面,三种角色分别对应着三张表

    超级管理员功能:

    添加读者添加工作人员查询读者信息查询工作人员信息注销借阅证修改读者密码修改工作人员密码修改密码

    工作人员功能

    查询读者信息管理借阅证查询书籍信息书籍入库修改书籍信息审核借阅记录违章信息审核违约查看个人信息修改密码

    读者功能

    热门推荐图书查询图书借阅图书预约图书归还查看个人信息查看当前借阅查看借阅历史查看预约信息查看违约记录修改密码



    0  留言 2021-09-26 17:30:18
  • 基于Springboot的宿舍管理系统——释心的毕设

    基于Springboot的宿舍管理系统——释心的毕设
    1.项目简介1.1背景分析宿舍管理主要在各个中学和高校中经常提到。宿舍管理是后勤部门的一个重要工作。但是现在很多后勤部门都还是在使用最原始的宿舍管理方法。而且在学生入住的过程中学生住宿的信息得不到有效的更新,同时学生经常会更换宿舍等等。
    1.2需求分析1.2.1宿舍管理现状这样,无法保证学生住宿信息的完整性。也就是说现在没有一个很好的办法来管理学生的住宿信息。这也是后勤管理的一个缺陷。
    1.2.2宿舍管理制度每个学校都会有自己的一套管理方法和管理制度。同时很多学校的管理方法都是大同小异。在宿舍管理过程中宿舍管理制度是一个依据,同时也是一种规范。
    1.2.3住宿管理状态入住
    每次新学期开始都会有很多新的面孔进入学校或者公司。他们的迎接安排工作也非常重要。
    调整
    在住宿过程中,很多时候学生或者员工会要求调整宿舍。他们可能出于不同的原因,在这个过程中很多合理的要求都会被楼管和宿舍管理部门所接受。
    离开
    当学生毕业或者员工离开的时候,需要做好宿舍信息的统计。统计还有多少宿舍铺位可以利用,已经有多少铺位被占用。
    1.2.4宿舍日常管理内容宿舍出入管理
    每天都有很多的同学出入宿舍,宿舍的安全是楼层管理人员和学校非常关心的问题。在很多学校开始实行一卡通,这个也是防范意外发生的好方法。在公司中的出入管理就相对比较复杂,这些只能依靠门卫来处理。
    宿舍财务管理
    不管是员工宿舍还是学生宿舍,财务管理是重中之重。其中包括水费管理,电费管理,还可能包括维修费管理。
    宿舍建设管理
    在宿舍的管理过程中,宿舍建设管理是也是很重要的事情。但是在实际的宿舍管理过程中没有得到很好的重视。
    1.2.5宿舍管理人物职责超管
    楼管是宿舍管理过程中的核心人物。他要管理公共场所的卫生,还有监督学生宿舍建设。同时也是宿舍管理制度的执行者。
    宿舍管理员
    宿舍管理员在宿舍管理过程中起到了协助作用。他们协助宿舍管理部门,楼管执行宿舍管理中的査宿等等。
    学生
    在学校,学生是学校宿舍管理的主体。相对而言,在公司,员工的宿舍管理要适当放松,因为很多员工的生活习惯是不相同的。只有在共同的文化建设上下功夫,宿舍管理才能更好的实施。
    1.3 运行环境1.3.1 服务器端环境操作系统:Windows 10
    数据库系统:SQL Server数据库
    可用内存:建议至少4096M
    1.3.2 客户端环境操作系统:Windows 7/8/10
    可用内存:建议至少4096M
    1.4技术栈基于springboot、jpa、thymeleaf、bootstrap、jsp、easypoi的宿舍管理项目
    2.数据库设计2.1表结构分析宿舍表

    来访记录表

    报到表

    登出表

    报修表

    宿舍评分表

    职工表

    学生信息表

    用户表

    2.2ER图
    3.项目开发3.1项目配置数据库配置
    spring.datasource.url=jdbc:mysql://127.0.0.1:3306/dorm?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMTspring.datasource.username=rootspring.datasource.password=123456spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.mvc.view.prefix=/WEB-INF/view/spring.mvc.view.suffix=.jsp#是否显示SQLspring.jpa.show-sql=true
    maven依赖
    <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.shixin</groupId> <artifactId>dormitory-management</artifactId> <version>0.0.1-SNAPSHOT</version> <name>dormitory-management</name> <description>大学生宿舍管理系统</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--easypoi--> <dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-base</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-web</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-annotation</artifactId> <version>3.2.0</version> </dependency> <!-- tomcat支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </repository> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </pluginRepository> </pluginRepositories></project>
    3.2视图层配置@Overridepublic void addInterceptors(InterceptorRegistry registry) { InterceptorRegistration interceptor = registry.addInterceptor(loginInterceptor); interceptor.excludePathPatterns("/login/toLogin"); interceptor.excludePathPatterns("/login"); interceptor.excludePathPatterns("/static/**"); interceptor.addPathPatterns("/**");}@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");}@Beanpublic InternalResourceViewResolver setupViewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/view/"); resolver.setSuffix(".jsp"); return resolver;}
    3.3登陆拦截器public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); UserExpand info = (UserExpand) session.getAttribute("LOGIN_USER"); if (info != null) { // 登录成功不拦截 return true; } else { response.sendRedirect(request.getContextPath() + "/login/toLogin"); return false; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // TODO Auto-generated method stub HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // TODO Auto-generated method stub HandlerInterceptor.super.afterCompletion(request, response, handler, ex); }}
    3.4常用工具类public class ExportExcelUtil { /** * 下载 * * @param response HttpServletResponse * @param fileName 文件名 * @param workbook Workbook */ public static void downLoadExcel(HttpServletResponse response, String fileName, Workbook workbook) { try { response.setCharacterEncoding("UTF-8"); response.setHeader("content-Type", "application/vnd.ms-excel"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".xls", "UTF-8")); workbook.write(response.getOutputStream()); } catch (Exception e) { e.printStackTrace(); } } /** * 设置sum公式 * * @param wk Workbook * @param sumCol 合计 * @param itemCol 合计的项 */ public static void setSumFormula(Workbook wk, Character sumCol, Character... itemCol) { StringBuffer buffer = new StringBuffer(); Sheet sheet = wk.getSheetAt(0); Row row = null; for (int i = sheet.getFirstRowNum() + 2; i <= sheet.getLastRowNum(); i++) { row = sheet.getRow(i); for (Character item : itemCol) { CellAddress address = row.createCell(colCharToNum(item)).getAddress(); buffer.append(address + ":"); } String substring = buffer.toString().substring(0, buffer.toString().lastIndexOf(":")); row.createCell(colCharToNum(sumCol)).setCellFormula(String.format("sum(%s)", substring)); buffer.setLength(0); } } /** * 列英文标识转数字列号 * * @param character char * @return */ private static Integer colCharToNum(Character character) { return (int) character - 65; }}
    3.5业务代码业务层
    @Overridepublic List<Stuinfo> findAll(UserExpand user) { if (user.getStaffinfo() != null) { Specification specification = (root, criteriaQuery, criteriaBuilder) -> criteriaBuilder.like(root.get("dormid"), user.getStaffinfo().getDormname() + user.getStaffinfo().getDormno() + "%"); return stuRepository.findAll(specification); } else { return stuRepository.findAll(); }}@Overridepublic Page<Stuinfo> findStus(Pageable pageable, UserExpand user, String searchId, String searchDormName) { if (user.getStaffinfo() != null) { return stuRepository.findAll(createSpe(searchId, searchDormName, user.getStaffinfo()), pageable); } else { return stuRepository.findAll(createSpe(searchId, searchDormName, null), pageable); }}public Specification createSpe(String searchId, String searchDormName, Staffinfo staffinfo) { List<Predicate> predicates = new ArrayList<>(); return (root, criteriaQuery, criteriaBuilder) -> { if (StringUtils.isNotEmpty(searchId)) { predicates.add(criteriaBuilder.equal(root.get("id"), searchId)); } if (StringUtils.isNotEmpty(searchDormName)) { predicates.add(criteriaBuilder.equal(root.get("grade"), searchDormName)); } if (null != staffinfo) { predicates.add(criteriaBuilder.like(root.get("dormid"), staffinfo.getDormname() + staffinfo.getDormno() + "%")); } predicates.add(criteriaBuilder.equal(root.get("status"), 0)); return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()])); };}@Override@Transactionalpublic Boolean importExcel(MultipartFile file) { try { List<Stuinfo> stuList = ExcelImportUtil.importExcel(file.getInputStream(), Stuinfo.class, new ImportParams()); stuRepository.saveAll(stuList); List<User> userList = stuList.stream().map(e -> { User user = new User(); user.setUsername(e.getId()); user.setPassword("123456"); user.setPermission(0); return user; }).collect(Collectors.toList()); userRepository.saveAll(userList); } catch (Exception e) { e.printStackTrace(); return false; } return true;}@Overridepublic Boolean leaveSchool(List<String> ids) { try { stuRepository.update(1, ids); } catch (Exception e2) { e2.printStackTrace(); return false; } return true;}@Overridepublic Boolean resetPwd(String stuId) { try { User user = userRepository.findByUsername(stuId); user.setPassword("123456"); userRepository.save(user); } catch (Exception e) { e.printStackTrace(); return false; } return true;}@Override@Transactionalpublic Boolean del(String stuId) { try { Stuinfo stuinfo = new Stuinfo(); stuinfo.setId(stuId); stuRepository.delete(stuinfo); User user = userRepository.findByUsername(stuId); userRepository.delete(user); } catch (Exception e) { e.printStackTrace(); return false; } return true;}@Overridepublic Boolean update(Stuinfo stuinfo) { try { stuRepository.save(stuinfo); } catch (Exception e) { e.printStackTrace(); return false; } return true;}@Overridepublic Boolean updatePhone(Stuinfo stuinfo) { try { stuRepository.updatePhone(stuinfo.getId(), stuinfo.getPhone()); } catch (Exception e) { e.printStackTrace(); return false; } return true;}
    控制层
    @PostMapping("/exportInfo")public void exportInfo(HttpSession session, HttpServletResponse response) { UserExpand user = (UserExpand) session.getAttribute("LOGIN_USER"); List<Stuinfo> list = stuServiceI.findAll(user); Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("学生信息", "学生信息表1"), Stuinfo.class, list); ExportExcelUtil.downLoadExcel(response, "学生信息表", workbook);}@GetMapping("/infoView")public String getInfoView(HttpSession session, Model model) throws Exception { UserExpand user = (UserExpand) session.getAttribute("LOGIN_USER"); Stuinfo stuinfo = stuServiceI.findById(user.getUsername()); model.addAttribute("stuinfo", new ObjectMapper().writeValueAsString(stuinfo)); return "stu/infoView";}@GetMapping("/updatePwd")public String updatePwd(HttpSession session, Model model) { UserExpand user = (UserExpand) session.getAttribute("LOGIN_USER"); Stuinfo stuinfo = stuServiceI.findById(user.getUsername()); model.addAttribute("id", stuinfo.getId()); return "stu/updatePwd";}@PostMapping("/updatePhone")@ResponseBodypublic Boolean updatePhone(Stuinfo stuinfo) { return stuServiceI.updatePhone(stuinfo);}@PostMapping("/updatePwd")@ResponseBodypublic Boolean updatePwd(String id, String oldPwd, String newPwd) { return stuServiceI.updatePwd(id, oldPwd, newPwd);}@GetMapping("/list")@ResponseBodypublic Page<Stuinfo> getStuInfo(@PageableDefault Pageable pageable, HttpSession session, String searchId, String searchDormName) { UserExpand user = (UserExpand) session.getAttribute("LOGIN_USER"); return stuServiceI.findStus(pageable, user, searchId, searchDormName);}@PostMapping("/importExcel")@ResponseBodypublic Boolean importExcel(@RequestParam("file") MultipartFile file) { return stuServiceI.importExcel(file);}@PostMapping("/leaveSchool")@ResponseBodypublic Boolean leaveSchool(@RequestBody(required = true) List<String> ids) { return stuServiceI.leaveSchool(ids);}@GetMapping("/resetPwd")@ResponseBodypublic Boolean resetPwd(String stuId) { return stuServiceI.resetPwd(stuId);}
    3.6视图层代码//初始化Tablefunction tableInit() { $('#tb_repairHistory').bootstrapTable({ url : '/stu/repairHistory', //请求后台的URL(*) method : 'get', //请求方式(*) cache : false, //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*) clickToSelect:true, sortable : true, //是否启用排序 sortOrder : "asc", //排序方式 sidePagination : "server", //分页方式:client客户端分页,server服务端分页(*) pagination : true, //是否显示分页(*) pageNumber : 1, //初始化加载第一页,默认第一页 pageSize : 10, //每页的记录行数(*) pageList : [10, 25, 50], //可供选择的每页的行数(*) uniqueId : 'dormid', //每一行的唯一标识,一般为主键列 sortName: 'dormid', // 要排序的字段 queryParams : function(params) { return { size: params.limit, // 每页要显示的数据条数 page: params.offset/params.limit, //pageable 下标从0开始 sort: params.sort + "," + params.order // 排序规则 } },//传递参数(*) responseHandler: function(res) { return { total : res.totalElements, //总页数,前面的key必须为"total" rows : res.content//行数据,前面的key要与之前设置的dataField的值一致. }; }, columns : [ { field : 'id', visible:false }, { field : 'dormid', title : '宿舍号', sortable : true }, { field : 'reason', title : '报修类型', formatter: function (value,row,index) { var result=""; if (value == 0) { result = "灯"; }else if(value == 1) { result = "床,桌椅"; }else if(value == 2) { result = "门窗"; }else if (value == 3){ result = "其它"; } return result; } }, { field : 'date', title : '报修时间', sortable : true, formatter: function (value,row,index) { if (value != null) { var date = new Date(value); return dateFtt("yyyy-MM-dd hh:mm",date); } } },{ field : 'note', title : '说明' },{ field : 'status', title : '状态', formatter: function (value,row,index) { var result=""; if (value == 2) { result = "处理完成"; } return result; } }] });};/** * 时间格式化处理 */function dateFtt(fmt,date) { var o = { "M+" : date.getMonth()+1, //月份 "d+" : date.getDate(), //日 "h+" : date.getHours(), //小时 "m+" : date.getMinutes(), //分 "s+" : date.getSeconds(), //秒 "q+" : Math.floor((date.getMonth()+3)/3), //季度 "S" : date.getMilliseconds() //毫秒 }; if(/(y+)/.test(fmt)) fmt=fmt.replace(RegExp.$1, (date.getFullYear()+"").substr(4 - RegExp.$1.length)); for(var k in o) if(new RegExp("("+ k +")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length))); return fmt; }</script></html>
    4.项目运行4.1学生用户登录

    主页

    个人信息

    申请保修

    入校登记

    离校登记

    宿舍评分查看

    4.2宿管用户主页

    学生信息

    处理报修单

    入校登记历史记录

    录入评分

    来访人员管理

    4.3超管宿舍楼信息管理

    学生信息管理

    职工信息管理

    5.总结这是大学期间的一次小作业,对springboot框架的学习也是从这里开始的,收获了很多
    0  留言 2021-09-26 16:46:43
  • 基于SSM实现的汽车门店管理平台系统

    基于SSM实现的汽车门店管理平台系统
    1.项目介绍1.1项目背景汽车产业被各国视为支柱型产业,在经济发展的过程中起着举足轻重的作用,全球经济日趋一体化,国际、国内汽车产业竞争越来越激烈,我国汽车产业也面临巨大的机会和挑战,所以采用国际先进的管理思想、现代的管理方式成为汽车产业可持续发展的重要保障之一,汽车产业的企业信息化管理是成为业价值链上的企业提升核心竞争力的不可或缺手段。
    在汽车产业价值链上包括汽车制造企业、汽车配件制造企业、汽车销售企业、旧车交易企业、汽车配件销售企业、汽车养护企业、汽车维修企业、汽车租赁企业和驾驶员培训企业等。CareBusiness Suite汽车销售服务管理系统是针对汽车销售企业、汽车养护企业、汽车维修企业和汽车配件企业开发的管理信息系统套件。
    CareBusiness Suite构建于CareBusiness平台,作为应用软件的通用基础,CareBusiness平台在多个行业软件中不断被重用,其稳定性得到持续的验证CareBusiness Suite涵盖汽车销售和服务产业的几乎所有业务环节,内置了科学的管理流程,集成了客户关系管理思想,既可以适用于业务单一的汽车服务企业(如只从事汽车销售,或者只从事汽车维修),也适合于包括多种业务种类的汽车服务企业。
    SSM项目,后台管理系统,训练的点有SSM、RBAC、Shiro等技术点
    1.2系统特点● CareBusiness Suite的子系统之间有良好的接口,子系统之间可以方便的交换数据,保持了数据的一致性。各个系统既可以独立地运行,也可以与其它子系统联合使用,汽车企业可以根据自身的特征选择相应的子系统及其模块,构建满足自身不同阶段需要的、个性化的企业管理信息系统。
    ●CareBusiness Suite基于流程而非单据的管理,内置科学的管理流程,实现了汽车企业业务流程化管理的需求。
    ● CareBusiness Suite集成客户关系管理思想,将企业的交易对象均视为企业的客户(包含法人客户、个人客户、代理商、合作伙伴和供应商等),细腻的个性化客户信息管理,所有的业务信息均与相应客户关联,使得客户历史信息和个性化信息成为客户关怀的重要线索,成为维护客户忠诚度和评估客户终身价值的重要依据。
    ● CareBusiness Suite支持Windows客户端和IE客户端,栏目布局以矩阵的形式安排,提供栏目跳转、历史线索轨迹和当前线索定位,真正实现360度的数据视图功能,用户使用极为方便。
    ● CareBusiness Suite将简单查询、复合查询、图表和报表分析集成到模块中,用户获取分析结果极为便捷。查询分析、图表分析和报表分析均针对当前数据集进行,真正做到为每一位用户提供决策支持信息,使得分析功能不再是层次管理者的专利。
    ● CareBusiness Suite的所有单据和表格可以导出至Excel、Word、HTML、TXT格式文件。支持各种单据(如销售订单、报价单、入库单、出库单和采购计划单等)的生成、预览和打印功能。
    ● CareBusiness Suite支持多币种和多计量单位的自动换算管理。
    1.3软件架构 CareBusiness Suite主要包含了汽车销售管理系统、汽车养护管理系统、汽车维修管理系统和汽车配件管理系统等系统模块,这些系统及其系列模块统一构建于CareBusiness 平台之上,模块之间既相对独立,又可以有机耦合。汽车销售服务企业可以根据自身的业务范围、特点和管理需要,按需选择其中的某些模块,组成自己的管理信息系统。
    功能
    CareBusiness Suite主要包含了汽车销售管理系统、汽车养护管理系统、汽车维修管理系统和汽车配件管理系统等系统模块,这些系统及其系列模块统一构建于CareBusiness 平台之上,模块之间既相对独立,又可以有机耦合。汽车销售服务企业可以根据自身的业务范围、特点和管理需要,按需选择其中的某些模块,组成自己的管理信息系统。
    1.4技术采用ssm、Freemaker、Shiro、RBAC、RCM、阿里云短信验证、邮箱服务
    1.5需求分析1.5.1 汽车销售管理: 汽车销售与普通商品销售有着极大的差别,在传统的汽车业管理模式中,纸单据及手工管理是其主流方式。这种方式带来是数据可靠性差,运行效率低下,统计分析难度大,抽取对企业有用信息的可能性极小!显然,这种传统的销售管理模式已经不能适应当今汽车销售企业的市场需求。采用先进管理模式来管理客户关系,采用信息化管理手段培源固本,成为企业提升竞争力的重要途径之一。
    汽车销售管理系统包括汽车销售机会管理、门店导购管理、试车管理、报价管理、订单管理和行动管理等销售管理模块,入库管理、出库管理和盘点管理等仓库管理模块,供应商管理、采购询价和采购订单等整车采购管理模块。
    对于综合提供整车销售、养护和维修等服务的企业,可以集成选用汽车养护管理等其它系统,共同为企业的信息管理提供支持。
    1.5.2 汽车维修管理: 随着国内汽车行业的发展,这个行业的规模将继续迅速扩大,市场也将更加规范和成熟,竞争更加激烈,汽车维修企业或有维修业务的修理厂、公司约有10万多家,汽车维修已经成为中国汽车产业的重要组成部分。近几年,随着计算机硬件行业的飞速发展,很多经营者正在考虑使用管理软件加强管理。
    汽车维修管理系统包括维修业务受理管理、维修派单管理、维修配件领料管理、维修车间管理管理、维修工绩效管理管理、维修结算管理和工具管理管理等。
    汽车修理服务主要是处理客户上门服务的业务,汽车施救业务纳入到在汽车养护管理系统中,汽车配件管理业务纳入到汽配管理系统中。三者组合使用,可以形成满足从事多种汽车服务业务企业的管理信息系统。
    1.5.3. 汽车配件管理: 中国汽车配件的经营者约有30多万家,随着社会的飞速发展,当今信息、效率已成为各行各业竞争的武器。在汽配行业中手工的纸和手工具管理己再不能适应市场经济的发展,汽车配件、因其车型之多,零件种类之多等,单靠手工作业管理则难达到科学、准确。电脑在汽配行业的应用,已成为社会发展的必然趋势。
    汽配管理系统是针对各汽配店日常的汽车配件的进出、产品的购销、帐款的结算等业务而专门开发的。由于汽配产品繁杂,手工记帐烦琐,不易于统计、分类等现实情况,可能会让您感到忙乱。汽配管理系统不仅能使您从繁琐忙乱的工作中解脱出来,还能为您提供全方位、多层次的系统管理,使您从此一身轻松。汽配管理系统包括配件销售管理、配件采购管理、配件仓库管理、应收应付管理等从事汽车养护和汽车维修的企业一般也包含汽配管理业务,汽配管理系统可以与汽车养护系统、汽车维修系统一道,共同满足您的要求。
    1.6典型案例福建迅速汽车俱乐部(Speed Automobile Association)是福建省首家与国际汽车联会FIA标准接轨的会员权益组织,并率先加入中国旅游车船协会(CTASA)。 SAA倡导现代汽车文化,积极建设专业化、网络化的汽车服务保障体系,SAA的服务宗旨是”迅速救援,驾车无忧”。
    客户的忠诚度是企业可持续发展的不竭动力源泉。引进客户关系管理理念,构建CRM系统,是维护客户关系,提升客户忠诚度的重要手段。为此,SAA委托倍特力-亿百合公司建设以CRM为核心的管理信息系统,成为福建省首家导入CRM系统的汽车服务企业,在会员管理、施救服务、汽车美容、代理中间业务和汽车没用用品管理等领域全面实现信息化管理。
    SAA管理信息系统的销售模块主要包括客户管理、联系人管理、会员管理、会员发卡管理、机会管理、产品管理、价格管理、合作伙伴管理;服务模块主要包括车辆信息管理、服务协议管理、维修保养服务管理、救援服务管理、服务回访管理、汽车保险管理、汽车年检管理、汽车美容管理和汽车美容用品销售管理;采购和仓库管理模块主要包括美容用品采购管理、美容用品入库管理、美容用品出库管理、盘点管理、安全客户管理、移库管理和调拨管理等;结算管理模块主要包括会员费结算、救援费结算、美容精品结算、年检代理费结算和保险代理费结算等。
    2.数据库设计2.1表结构活动表

    预约表

    门店表

    投票表

    订单表

    业务分类表

    部门表

    员工表

    菜单表

    留言表

    公告表

    权限表

    角色表

    工资表

    2.2ER图
    3.项目实现3.1项目配置<!-- 关联 db.properties 文件 --><context:property-placeholder location="classpath:db.properties"/><!-- 配置 DataSource bean --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/></bean><!-- 配置 SqlSessionFactory bean --><bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory"> <property name="dataSource" ref="dataSource"/> <property name="typeAliasesPackage" value="cn.linstudy.domain"/> <property name="mapperLocations" value="classpath:cn/linstudy/mapper/*.xml"/> <!-- 注意其他配置 --> <property name="plugins"> <array> <bean class="com.github.pagehelper.PageInterceptor"> <property name="properties"> <!--使用下面的方式配置参数,一行配置一个,下面配的是合理化分页 --> <value> pageSizeZero=true reasonable=true </value> </property> </bean> </array> </property></bean><!-- 配置 SqlSessionFactory bean --><!-- 关联主配置文件 目前可以不配置--><!-- 配置别名 若不用别名,可以不配置 --><!-- 配置数据源--><!-- 关联 Mapper XML 可以不配置, 前提编译 Mapper 接口字节码文件与 Mapper XML 文件在一起,文件名也一样 --><!-- 配置 Mapper 接口的实现类对象 --><!-- 指定 Mapper 接口所在包 --><bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="cn.linstudy.mapper"/></bean><!-- 配置 IoC DI 注解解析器 , 让 Spring 帮我们创建业务接口的实现类对象, 完成字段注入 --><context:component-scan base-package="cn.linstudy.service"/><!-- 配置事务管理器 WHAT--><bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager"> <property name="dataSource" ref="dataSource"/></bean><!-- 配置增强, WHEN, 并关联上面 WHAT--><tx:advice id="interceptor" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="get" read-only="true"/> <tx:method name="select" read-only="true"/> <tx:method name="list" read-only="true"/> <tx:method name="query" read-only="true"/> <tx:method name="count" read-only="true"/> <tx:method name="*"/> </tx:attributes></tx:advice><!-- 配置 AOP --><aop:config> <aop:pointcut id="txPoint" expression="execution(* cn.linstudy.service.impl.*ServiceImpl.*(..))"/> <aop:advisor advice-ref="interceptor" pointcut-ref="txPoint"/></aop:config><!-- WHERE --><!-- 关联 WHERE WHEN--><!--开启shiro注解扫描--><aop:config/><!-- Pointcut advisor通知器, 会匹配所有加了shiro权限注解的方法 --><bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/></bean>
    3.2安全框架shiro认证// 认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 通过token获取用户名(用户登录的时候) String username = (String) token.getPrincipal(); // 判断是否存在在数据库 Employee employee = employeeService.selectByUsername(username); if (employee != null) { // 说明此时用户名是对的,返回一个身份对象 return new SimpleAuthenticationInfo(employee, employee.getPassword(), this.getName()); } return null;}// 授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 创建info对象 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 获取当前登录主体对象 //Subject subject = SecurityUtils.getSubject(); // 获取主体的身份对象(这里获取的对象与认证方法doGetAuthenticationInfo返回的SimpleAuthenticationInfo对象的第一个参数是同一个对象) Subject subject = SecurityUtils.getSubject(); Employee employee = (Employee) subject.getPrincipal(); // 判断是否是超级管理员 if (employee.getAdmin()) { info.addRole("admin"); // 给他所有的权限 info.addStringPermission(" *:* "); } else { // 通过员工id拿到所有的角色 List<Role> roles = employeeService.selectRolesById(employee.getId()); for (Role role : roles) { info.addRole(role.getSn()); } //通过员工id查询出所有的权限 List<String> permissionByEmployeeId = employeeService .getPermissionByEmployeeId(employee.getId()); info.addStringPermissions(permissionByEmployeeId); } return info;}
    public class ShiroFreeMarkerConfig extends FreeMarkerConfigurer { @Override public void afterPropertiesSet() throws IOException, TemplateException { //继承之前的属性配置,这不能省 super.afterPropertiesSet(); Configuration cfg = this.getConfiguration(); cfg.setSharedVariable("shiro", new ShiroTags());//注册shiro 标签,这里可以换成自己想要其他的标签,但是一般建议是用shiro }
    3.3全局异常捕捉// 标记该类为Controller的增强类,用于捕获异常@ControllerAdvicepublic class ExceptionControllerAdvice { // @ExceptionHandler(异常类型.class)需要处理Controller抛出什么类型的异常. @ExceptionHandler(CarBussinessException.class) public void handleBussinessException(CarBussinessException carBussinessException, HttpServletResponse response, HandlerMethod handlerMethod) throws IOException { carBussinessException.printStackTrace(); // 判断是返回页面还是返回JSON ResponseBody methodAnnotation = handlerMethod.getMethodAnnotation(ResponseBody.class); if (methodAnnotation == null) { // 返回页面 response.sendRedirect("error"); } else { response.setContentType("application/json;charset=utf-8"); String responseData = JSON .toJSONString(new ResponseResult(false, carBussinessException.getMessage())); response.getWriter().write(responseData); } } @ExceptionHandler(Exception.class) public void BussinessException(Exception exception, HttpServletResponse response, HandlerMethod handlerMethod) throws IOException { exception.printStackTrace(); ResponseBody methodAnnotation = handlerMethod.getMethodAnnotation(ResponseBody.class); if (methodAnnotation == null) { response.sendRedirect("/error"); } else { response.setContentType("application/json;charset=utf-8"); String responseData = JSON.toJSONString(new ResponseResult(false, exception.getMessage())); response.getWriter().write(responseData); } } @ExceptionHandler(AuthorizationException.class) public String BussinessException(AuthorizationException exception, HttpServletResponse response, HandlerMethod method) throws IOException { exception.printStackTrace(); //方便开发的时候找bug //如果原本控制器的方法是返回jsonresult数据,现在出异常也应该返回jsonresult //获取当前出现异常的方法,判断是否有ResponseBody注解,有就代表需要返回jsonresult if (method.hasMethodAnnotation(ResponseBody.class)) { try { response.setContentType("application/json;charset=UTF-8"); response.getWriter().print(JSON.toJSONString(new ResponseResult(false, "没有权限操作"))); } catch (IOException e1) { e1.printStackTrace(); } return null; } //如果原本控制器的方法是返回视图页面,现在也应该返回视图页面 return "common/nopermission"; }}
    3.4登陆拦截器@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //请求是静态资源,handler对应的类 class org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler //请求是动态资源,handler对应的类class org.springframework.web.method.HandlerMethod // 如果是动态资源 if (handler instanceof HandlerMethod) { Employee employee = (Employee) request.getSession().getAttribute("EMPLOYEE_IN_SESSION"); if (employee == null) { response.sendRedirect("/login.html"); return false; } // 查看未读公告的数量 int unReadNumber = noticeService.unReadNumber(employee.getId()); // 查询未读公告 List<Notice> unReadNotice = noticeService.unReadNotice(employee.getId()); for (Notice notice : unReadNotice) { notice.setCalTime(RelativeDateUtils.format(notice.getCreateTime())); } request.getSession().setAttribute("unReadNumber", unReadNumber); request.getSession().setAttribute("unReadNotice", unReadNotice); } return true; }}
    3.5常用工具类邮箱工具
    public static boolean sendEmail(String emailAddress, String code) { try { //不用更改 HtmlEmail email = new HtmlEmail(); //需要修改,126邮箱为smtp.126.com,163邮箱为163.smtp.com,QQ为smtp.qq.com email.setHostName("smtp.qq.com"); email.setCharset("UTF-8"); // 收件地址 email.addTo(emailAddress); //此处填邮箱地址和用户名,用户名可以任意填写 email.setFrom("***", ""); // 此处填写邮箱地址和客户端授权码 email.setAuthentication("***", "***"); //此处填写邮件名,邮件名可任意填写 email.setSubject("***"); //此处填写邮件内容 email.setMsg("尊敬的用户您好,您本次注册的验证码是:" + code); email.send(); return true; } catch (Exception e) { e.printStackTrace(); return false; }
    文件操作
    public static String uploadFile(MultipartFile file, String path) throws Exception { //获取随机值 String uuid = UUID.randomUUID().toString(); //获取文件原本的名字 String fileName = file.getOriginalFilename(); //获取拓展名,含头不含尾 String fileType = fileName.substring(fileName.lastIndexOf(".")); // 拼接上传后的文件名称 fileName = "/upload/" + uuid + fileType; File targetFile = new File(path, fileName); //把输入流传进去, 会把内容写到目标文件 FileUtils.copyInputStreamToFile(file.getInputStream(),targetFile); return fileName;}/** * 删除文件 * @param pic */public static void deleteFile(String pic) { File file=new File(pic); if(file.exists()) file.delete();}
    验证码生成
    /** * 使用系统默认字符源生成验证码 * @param verifySize 验证码长度 * @return */public static String generateVerifyCode(int verifySize){ return generateVerifyCode(verifySize, VERIFY_CODES);}/** * 使用指定源生成验证码 * @param verifySize 验证码长度 * @param sources 验证码字符源 * @return */public static String generateVerifyCode(int verifySize, String sources){ if(sources == null || sources.length() == 0){ sources = VERIFY_CODES; } int codesLen = sources.length(); Random rand = new Random(System.currentTimeMillis()); StringBuilder verifyCode = new StringBuilder(verifySize); for(int i = 0; i < verifySize; i++){ verifyCode.append(sources.charAt(rand.nextInt(codesLen-1))); } return verifyCode.toString();}/** * 生成随机验证码文件,并返回验证码值 * @param w * @param h * @param outputFile * @param verifySize * @return * @throws IOException */public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException{ String verifyCode = generateVerifyCode(verifySize); outputImage(w, h, outputFile, verifyCode); return verifyCode;}/** * 输出随机验证码图片流,并返回验证码值 * @param w * @param h * @param os * @param verifySize * @return * @throws IOException */public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException{ String verifyCode = generateVerifyCode(verifySize); outputImage(w, h, os, verifyCode); return verifyCode;}/** * 生成指定验证码图像文件 * @param w * @param h * @param outputFile * @param code * @throws IOException */public static void outputImage(int w, int h, File outputFile, String code) throws IOException{ if(outputFile == null){ return; } File dir = outputFile.getParentFile(); if(!dir.exists()){ dir.mkdirs(); } try{ outputFile.createNewFile(); FileOutputStream fos = new FileOutputStream(outputFile); outputImage(w, h, fos, code); fos.close(); } catch(IOException e){ throw e; }}/** * 输出指定验证码图片流 * @param w * @param h * @param os * @param code * @throws IOException */public static void outputImage(int w, int h, OutputStream os, String code) throws IOException{ int verifySize = code.length(); BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); Random rand = new Random(); Graphics2D g2 = image.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); Color[] colors = new Color[5]; Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN, Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.YELLOW }; float[] fractions = new float[colors.length]; for(int i = 0; i < colors.length; i++){ colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)]; fractions[i] = rand.nextFloat(); } Arrays.sort(fractions); g2.setColor(Color.GRAY);// 设置边框色 g2.fillRect(0, 0, w, h); Color c = getRandColor(200, 250); g2.setColor(c);// 设置背景色 g2.fillRect(0, 2, w, h-4); //绘制干扰线 Random random = new Random(); g2.setColor(getRandColor(160, 200));// 设置线条的颜色 for (int i = 0; i < 20; i++) { int x = random.nextInt(w - 1); int y = random.nextInt(h - 1); int xl = random.nextInt(6) + 1; int yl = random.nextInt(12) + 1; g2.drawLine(x, y, x + xl + 40, y + yl + 20); }
    3.6业务代码/** * @Description:查询所有门店 * @author XiaoLin * @date 2021/3/14 * @Param: [qo, model] * @return java.lang.String */ @RequestMapping("list") public String listAll(@ModelAttribute("qo") BusinessQueryObject qo, Model model){ PageInfo<Business> businessPageInfo = businessService.selectForPage(qo); model.addAttribute("pageInfo",businessPageInfo); return "/business/list"; }/** * @Description:增加或者删除门店 * @author XiaoLin * @date 2021/3/14 * @Param: [id, model] * @return java.lang.String */ @RequestMapping("saveOrUpdate") public String saveOrUpdate(Long id,Model model){ // id不为空说明是编辑,根据id查询门店,放进model对象中 if (id != null){ model.addAttribute("business",businessService.selectByPrimaryKey(id)); } // 否则就直接跳转 return "/business/input"; } // 为获取真实路径用 @Autowired ServletContext servletContext; /** * @Description:修改/增加门店 * @author XiaoLin * @date 2021/3/14 * @Param: [business] * @return java.lang.String */ @RequestMapping("updateAndSave") public String update(Business business , MultipartFile file) throws Exception { if (business.getId() != null){ // 说明文件不为空,那么就上传营业执照 if (file != null && file.getSize() >0){ // 获得webapp的真实路径 String realPath = servletContext.getRealPath("/"); // 我们在编辑图片之前,要先看看该公司是否拥有过图片,如果有先删除 if (StringUtils.hasText(business.getLicenseImg())){ String deletePath = realPath + business.getLicenseImg(); FileUploadUtil.deleteFile(deletePath); } String filePath = FileUploadUtil.uploadFile(file, realPath); business.setLicenseImg(filePath); } businessService.updateByPrimaryKeySelective(business); return "redirect:/business/list"; }else { if (file != null && file.getSize()>0){ String realPath = servletContext.getRealPath("/"); String filePath = FileUploadUtil.uploadFile(file, realPath); business.setLicenseImg(filePath); } businessService.insertSelective(business); return "redirect:/business/list"; } }
    4.项目展示登录

    主页

    部门管理

    员工管理

    工资管理

    角色管理

    字典管理

    数据报表

    公告管理

    留言管理

    订单管理

    5.总结通过这次项目的开发,我对数据加密的方式更加了解了,其中加密技术主要可以分为以下几种

    不可逆加密算法: 只能加密不能解密 md5 一般对登录密码处理可逆加密算法: 可以加密,也可以解密 又可以分为是否对称,主要是看秘钥是否是同一个,就是对称,否则就是不对称

    对称加密算法:DES,AES等 数据库密码进行加密密文为s 加解密算法为AES 秘钥为k,明文为c ;加密:s = AES(k,c)解密:c = AES(k,s)非对称加密算法:RSA 网络传输数据加密密码是成对出现的,一个私钥就对应一个公钥。如果使用私钥加密,只能使用与之对应公钥来解决。反之如果使用公钥加密,只能使用与之对应私钥解密
    0  留言 2021-09-24 18:12:19
  • 基于Jsp和MySQL实现的校园二手物品交易系统

    摘 要校园二手物品交易系统主要用于解决处理学生在校期间遗留下各种二手物品的交易问题,同时,交易平台也给在校学生提供新物品需求。广交地稀人广,宿舍资源更是供不应求。有些闲置物品食之无味,弃之可惜,关键是极大地占用了宿舍空间。阳光校园二手交易平台是以广交院为平台而设计的二手交易网,利用简单快捷的交易方式为广交大学生提供便利的二手物品交流平台。
    本文研究了一个校园二手物品交易系统,该系统基于B/S架构模式,使用SSM框架开发,并根据现有的网络二手交易系统设计优化而成。系统主要以Java语言作为开发基础,使用了Jsp+Sping+SpringMVC+Mybatis等技术,采用MyEclipse作为开发工具,以MySql作为数据库工具,使用Tomcat作为Web服务 器。本系统分为前台模块和后台管理模块,其中前台模块实现了物品分类、物 品详情、用户注册、用户登录、物品发布、在线支付和用户个人中心等功能; 后台管理模块实现用户管理、物品管理、订单管理、钱包管理和系统设置等功能。本系统功能比较完善,界面友好,操作简单,方便在校生实现资源再利用。
    利用现代信息技术手段实现的校园二手物品网络交易大大减低了物品在交 易过程中的成本,更重要的是,这些交易过程不会受到空间和时间上的限制,所以无论从提升校园整体形象上还是从经济利益上,都有着十分重要的意义。
    关键词:校园二手物品,交易系统, SSM,Jsp,MySql,maven框架
    第一章 绪论1.1 设计背景、目的及意义1.1.1 设计背景“二手市场”实际上就是旧货市场。而就校园二手市场的交易物品类别比较丰富,例如日常用品、电子设施、书刊文献等均为校园二手市场里普遍存在的物品,并且因学生的日常用品具有较强的重复应用特性与学生本身的不稳定性因素,让校园二手市场存在着较为稳定的需要,此类二手市场的存在增加了资源的应用率,应该得到大家鼓励和认同的。然而因为校园二手市场的运营制度存在较大的漏洞,所以应创建一个科学合理的治理制度来实现规范管理,进而推动二手物品此类资源的合理分配,同时还提高了学校的治理。
    随着互联网和网络购物日益深入社会生活,以网站作为信息交流平台,进行信息交流、购物供需等等已成为大学生不可或缺的生活方式。技术的不断发展以及产品的不断更新换代使得人们对物质文化需要越来越高,随之而来的问题便是二手物品日积月累却得不到更好的利用,发挥其更大的价值。特别是在校大学生手里一般会有较多的二手物品,其通用性也比较广泛,在这种情况下,校园二手交易网的重要性不言而喻。利用互联网的强大性构建一个校园二手交易平台,不仅有利用人们发挥物品的最大价值,同时也对人际交流,信息沟通有着极好的促进作用。
    1.1.2 设计目的和意义近年来,在国家不断倡导节俭型校园的精神推动下,大部分高校己经形成了二手物品交易的热潮。二手物品的交易与再利用体现了当代大学生节约环保 的生活理念与校园文化。每一年大一新生的到校就意 味着即将有一届毕业生就要离开校园,走向工作岗位,他们不可能将几年来留存下的书籍、生活用品等都带走,甚至有些物品己成为累赘,这时出售或者转让是为一种不错的选择, 这样大量二手物品的交易需求在高校大学生中一年年传承。大多数大学生的消费水平并不高,都希望能够买到物美又价廉的物品,通过校园内的二手交易跳蚤市场寻找自己需要的廉价物品是现阶段的主要途径,然而校内的跳蚤市场往往时间短暂,都集中在毕业季,毕业生一走,大规模的跳蚤市场就会消失,很难彻底便利的满足广大学子的交易需求,并且高校跳蚤市场在促进大学生节约环保意识的同时,却伴随着影响校园正常秩序的阴影。
    随着高校教育信息化技术的不断普及和深化,计算机和因特网已经成为高校师生日常生活不可或缺的一部分, Internet技术给传统高校二手交易带来了新的生机。通过Internet技 术建设一个校园二手交易平台使交易都通过网络进行,完美的满足了广大学子的交易需求,也解决了高校的日常管理问题。
    基于以上原因,选择”校园二手物品交易系统的设计与实现”既符合校园的文化与情怀,也强化了校园跳蚤市场的网络化信息发布与交易。同时,搭建针对校园二手网络交易网也是为了响应党的十八大提出的”节能减排”的号召,能够充分合理的利用二手物品,体现出可持续发展的要求,减少不可再生能源的浪费,保护我们共同生活的家园。更重要的是能够满足在校师生快速节奏的生活方式,满足他们的供求需要,为双方搭建一个信任交易的平台。
    第二章 相关技术介绍2.1 JavascriptJavaScript是一种基于对象和事件驱动并具有相对安全性的客户端脚本语言。同时也是一种广泛用于客户端Web开发的脚本语言,常用来给HTML网页添加动态功能,比如响应用户的各种操作。
    2.2 AjaxAjax全称为”Asynchronous JavaScript and XML”(异步JavaScript和XML), 是指一种创建交互式网页应用的网页开发技术。Ajax技术可以提供高度交互的 Web应用,给予用户更丰富的页面浏览体验,Ajax功能的实现主要依靠XMLHttpRequest对象及其属性和方法、发送请求和处理响应。
    2.3 MySQLMySQL是一个开放源码的小型关联式数据库管理系统,被广泛地应用在Internet上的中小型网站中。由于其体积小速度快、总体拥有成本低,尤其是开放源码这一特点,许多中小型网站为了降低网站总体拥有成本而选择了MySQL作为网站数据库。
    2.4 SSM框架SSM(Spring+SpringMVC+MyBatis)框架集由Spring、MyBatis两个开源框架整合而成(SpringMVC是Spring中的部分内容) 。常作为数据源较简单的web项目的框架。
    Sping
    Spring是一个开源框架,是于2003年兴起的一个轻量级的Java开发框架由Rod Johnson在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。
    SpringMVC
    Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web FIow里面。Spring MVC分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。
    SpringMVC在项目中拦截用户请求,它的核心Servlet即DispatcherServlet承担中介或是前台这样的职责,将用户请求通过HandlerMapping去匹配Controller, Controller就是具体对应请求所执行的操作。SpringMVC相当于SSH框架中 struts。
    Mybatis
    MyBatis是一个基于Java的持久层框架,mybatis是对jdbc的封装,它让数据库底层操作变的透明。mybatis的操作都是围绕一个sqlSessionFactory实例展开的。mybatis通过配置文件联到各实体类的Mapper文件,Mapper文件中配置了每个类对数据库所需进行的sql语句映射。在每次与数据库交互时,通过 sqlSessionFactory拿到一个sqlSession, 再执行sql命令。
    页面发送请求给控制器,控制器调用业务层处理逻辑,逻辑层向持久层发送请求,持久层与数据库交互,后将结果返回给业务层,业务层将处理逻辑发送给控制器,控制器再调用视图展现数据。
    2.5 Maven框架Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件。
    Maven 除了以程序构建能力为特色之外,还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性,所以常常用两三行 Maven 构建脚本就可以构建简单的项目。由于 Maven 的面向项目的方法,许多 Apache Jakarta 项目发文时使用 Maven,而且公司项目采用 Maven 的比例在持续增长。
    2.6 JSPJSP本是一个简化的Servlet设计,有点类似ASP技术,它是在传统的网页HTML (标准通用标记语言的子集)文件(*.htm,* .html)中插入Java程序段(Scriptlet)和JSP标记(tag),从而形成JSP文件,后缀名为(*.jsp)。用JSP开发的Web应用是跨平台的,既能在Linux 下运行,也能在其他操作系统上运行。
    JSP技术使用Java编程语言编写类XML的tags和scriptlets,来封装产生动态网页的处理逻辑。网页还能通过tags和scriptlets访问存在于服务端的资源的应用逻辑。JSP将网页逻辑与网页设计的显示分离,支持可重用的基于组件的设计,使基于Web的应用程序的开发变得迅速和容易。JSP(JavaServer Pages) 是一种动态页面技术,它的主要目的是将表示逻辑从Servlet中分离出来。
    2.7 B/S模式B/S(Browser/Server)结构即浏览器和服务器结构。它是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构。在这种结构下,用户工作界面是通过WWW浏览器来实现,极少部分事务逻辑在前端(Browser) 实现,但是主要事务逻辑在服务器端(Server) 实现,形成所谓三层结构。这样就大大简化了客户端电脑载荷,减轻了系统维护与升级的成本和工作量,降低了用户的总体成本(TCO) 。以目前的技术看,局域网建立B/S结构的网络应用,并通过Internet/Intranet模式下数据库应用,相对易于把握、成本也是较低的。它是一次性到位的开发,能实现不同的人员,以不同的接入方式访问和操作共同 的数据库;它能有效地保护数据平台和管理访问权限,服务器数据库也很安全
    B/S模式应用系统网络结构图

    2.8 BootStrapBootstrap是美国Twitter公司的设计师Mark Otto和Jacob Thornton合作基于HTML、CSS、JavaScript 开发的简洁、直观、强悍的前端开发框架,使得 Web开发更加快捷。Bootstrap提供了优雅的HTML和CSS规范,它即是由动态 CSS语言Less写成。
    2.9 系统开发平台及运行环境2.9.1 系统开发平台MyEclipse
    MyEclipse企业级工作平台(MyEclipse Enterprise Workbench,简称MyEcIipse)是对Eclipse IDE的扩展,利用它我们可以在数据库和JavaEE的开发、发布,以及应用程序服务器的整合方面极大的提高工作效率。它是功能丰富的JavaEE集成开发环境,包括了完备的编码、调试、测试和发布功能,完整支持HTML, Struts, JSP, CSS, Javascript, SQL, Hibernate。MyEclipse企业级工作平台(MyEclipse Enterprise Workbench,简称MyEclipse)是对Eclipse IDE的扩展,利用它我们可以在数据库和JavaEE的开发、发布,以及MyEclipse企业级工作平台(MyEclipse Enterprise Workbench,简称MyEclipse) 是对Eclipse ID E的扩展,利用它我们可以在数据库和JavaEE的开发、发布,以及应用程序服 务器的整合方面极大的提高工作效率。它是功能丰富的JavaEE集成开发环境,包括了完备的编码、调试、测试和发布功能,完整支持HTML, Struts, JSF, CSS, Javascript, SQL, Hibernate。
    Tomcat服务器
    Tomcat是一个小型的轻量级应用服务器,在中小型系统和并发访问用户 不是很多的场合下被普遍使用,是开发和调试JSP程序的首选。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache服务器,可利用它响 应对HTML页面的访问请求。实际上Tomcat部分是Apache服务器的扩展,但它是独立运行的,所以当你运行Tomcat时,它实际上作为一个与Apache 独立的进程单独运行的。
    Tomcat的环境主要有以下几方面技术优势:

    Tomcat中的应用程序是一个WAR (Web Archive)文件。WAR是Sun提出的一种Web应用程序格式,与JAR类似,也是许多文件的一个压缩包
    在Tomcat中,应用程序的部署很简单,你只需将你的WAR放到Tomcat的webapp目录下,Tomcat会自动检测到这个文件,并将其解压
    Tomcat不仅仅是一个Servlet容器,它也具有传统的Web服务器的功 能:处理htmI页面
    Tomcat也可以与其它一些软件集成起来实现更多的功能

    2.9.2 运行环境
    操作系统: Windows 7以上版本
    服务器软件: Tomcat7.0以 上版本
    浏览器: IE、Fire Fox、Google Chrome。

    第三章 系统需求分析阳光二手校园交易平台系统开发意图在于帮助校园师生更好的处理闲置物品。应用目标是确保每个用户都能完整合理地利用资源。本二手交易平台管理系统的用户包括系统管理员和普通用户和游客。系统管理员负责交易平台的管理工作,如各种基本信息的录入、修改、删除、查询、统计和管理系统用户等功能。普通用户使用该系统完成自己基本信息或者交易物品的基本信息的查询与统计管理等功能。游客使用该系统完成相关物品查询等。
    3.1 功能需求分析校园二手物品交易系统是根据各大高校二手市场的实际情况按照网络化的需求开发的,它的目标非常明确,即通过建立高校二手网络交易平台,将原来定时定点摆摊式的二手物品线下交易方式转变成通过网络平台进行交易的线上模式,使校园二手交易更加便捷、安全、规范和有针对性。
    系统功能需求整体上分为用户使用功能和系统管理功能,其中用户使用功 能包括用户浏览物品、用户登录、用户注册、用户搜索物品、用户发布物品、用户查看个人信息等功能;系统管理功能包括管理员管理物品分类、管理员管理物品、管理员管理订单、管理员管理用户等功能。
    根据以上功能需求分析,通过用例图来描述系统的主要功能。构建用例模型的第一步是确定模型中的使用者有哪些,确定使用者的原则有:谁是系统的 维护者、谁是系统的参与者等。维护者处于系统内部,对系统有绝对的控制权;而参与者-般都位于系统的外部,处于系统的控制之外。
    现在确定本系统用例模型有三种,分别是游客、注册用户和系统管理员。下面分别对这三个角色的功能进行描述:
    3.1.1 游客游客是未注册的用户,他们可以浏览物物品,可以搜索物品,如需购买物品,必须先注册成为网站用户。游客主要功能如下(图3-1为游客用例图):

    浏览物品
    搜索物品
    注册成为网站用户


    3.1.2 注册用户注册用户是经过网站合法认证的用户,登录网站后可以浏览物品、搜索物品、发布物品、关注物品、购买物品和查看个人中心。注册用户主要功能如下(图3-2为注册用户用例图):

    3.1.3 系统管理员系统管理员主要负责系统的后台管理工作,主要功能如下(图3-3为系统管理员用例图):

    在确定了系统用户和用户功能后就可以构建校园二手物品交易系统的用例图了,整个系统的用例图如图3-4系统总体用例图所示:

    3.2 非功能需求分析
    系统的实用性:系统的实用性是指系统设计开发的功能要尽量简单、实用,用户在使用系统过程中能够感受到系统的快捷、方便,不存在很多累赘和多余的操作或者功能
    系统的安全性:校园二手物品交易系统中记录了重要用户信息,包括用户的个人隐私信和、账户金额等信息,这些信息要具有很高的保密性和经济价值。因此,要求系统要具有一定的安全性,能够保证重要数据信息不被轻易窃取和破坏
    系统的稳定性:系统稳定性差则预示着系统在用户使用时,可能会出现数据操作错误,页面响应时间过长或者干脆无法响应等,因此系统的稳定性是用户对系统评价的重要指标之一。系统应采用稳定的操作系统、数据库、中间件等,以保证系统的稳定性
    系统的开放性:系统的开放性是指系统具有良好的可兼容性,可以在Windows的大部分版本的操作系统中正常的运行,另外,也支持不同浏览器版本,能够在微软的IE浏览器、谷歌浏览器等常用的浏览器上正常运行。系统的易升级和管理也是系统开放性的表现

    3.3 可行性分析可行性分析主要是指在当前己有的具体条件下,网站系统的开发是否己具备了必要的条件和资源,分析概括起来包括网站经济可行性、网站技术可行性分析分析和网站操作可行性分析三个方面。
    3.3.1 经济可行性网站的经济可行性分析主要是指网站的开发成本与收益之间的评估,分析网站建设带来的经济效益以及建设维护网站所需费用。

    网站所需费用。由于本网站系统是立足于校园,加之学院鼓励大学生自主创业,通过申请得到一台配置较高的服务器,开发团队由本人组织相关学生自主研发,成本相对较低
    通过调查研究,我校90%以上的学生希望能购买到二手书籍及相关学习用品,80%以上学生不介意购买电子产品,主要愿意是这些产品更新较快,没有必要花费那么多金钱购买全新的产品,75%以上的学生想要购买诸如体育用品和生活用品等,而据另一项调查,85%以上的同学都愿意出售自己的一些二手物品,而且70%的同学有过摆地摊出售二手物品的经历。因此,建立一个专门针对我校学生的二手物品交易网络平台是必要的。一是可以提高学校的整体形象,加强学校的管理,二是可以为学生减少损失

    3.3.2 技术可行性本系统基于Jsp+SSM+Tomcat+MySQL+Maven, 并采用B/S模式,由于JSP、SSM功能强大,而Tomcat和MySQL灵活易维护在开发方面具有方便快捷、使用灵活的特点,以及目前的广泛实际应用,因此使用JSP、SSM、Tomcat、MySQL和Maven是开发轻平台的最佳组合从而说明本系统在技术方面可行。
    硬件方面,科技飞速发展的今天,硬件更新的速度越来越快,容量越来越大,可靠性越来越高,价格越来越低,其硬件平台完全能满足此系统的需要。
    3.3.3 操作可行性本系统是基于B/S架构的,与传统的BBS发布信息非常相似,用户不需要进行特别的学习就可以实现物品购买和物品信息的发布。而对于系统的管理员,由于会配备系统管理的相关说明书,即使不是专业学科的系统管理员也可以很方便快捷地操作后台的管理系统。
    第四章 系统设置系统设计是把用户需求转化为系统的最重要开发环节,解决了”应该怎么做系统”的问题。在本章节中,主要是在系统需求分析的基础上,对系统架构、系统功能模块设计、系统工作流程设计和系统数据库设计进行阐述。
    4.1系统框架校园二手物品交易系统采用SSM(Spring MVC+Spring+Mybatis)框架开发,是标准的MVC模式,将整个系统划分为views层,controllers层,services层,mappers层四层。其中,Spring MVC负责请求的转发和视图管理,Spring实现业务对象管理,Mybatis作为数据对象的持久化引擎。整个系统架构运行流程如图4-1所示:


    views层:与controllers层结合比较紧密,需要二者结合起来协同工发,主要负责前台Jsp页面的表示
    controllers层:控制器,导入services层,因为services中的方法是我们使用到的,controllers通过接收前端传过来的参数进行业务操作,在返回一个指定的路径或者数据表
    services层:存放业务逻辑处理,也是一些关于数据库处理的操作,但不是直接和数据库打交道,它有接口还有接口的实现方法,在接口的实现方法中需要导入mappers层,mappers层是直接跟数据库打交道的,它也是个接口,有方法名字,具体实现方法也在里面,services是供我们使用的方法
    mappers层:对数据库进行数据持久化操作,它的方法语句是直接针对数据库操作的,而service层是针对我们controller,也就是针对我们使用者

    4.2 系统功能模块设计实质上,校园二手物品交易系统的综合性相对较强,复杂程度相对较高,可对现有软件进行充分利用,进行系统设计与规划。构建完善成熟的校园二手物品交易系统,其中涉及到以下内容,即前台网页界面、处理程序、MySQL 后台数据库系统等,在网站页面中显示出以下内容,例如物品图片、物品名称、物品价格、物品信息等。处理程序其实也就是对用户提交表单与相关操作进行处理,存储在后台数据库的信息有用户数据、物品数据和订单数据等。
    因此,校园二手物品交易系统需要具备前台功能和后台功能,其中,前台功能实现以下功能,用户注册、用户登录、物品推荐、物品分类、物品搜索、物品发布、物品详情、物品求购、我的主页。系统前台功能如图4-2所示:

    系统后台功能实现以下功能,物品分类管理、物品管理、订单管理、用户管理。系统后台功能如图4-3所示:

    4.3 系统工作流程设计系统工作流程包含用户工作流程和管理员工作流程,如图4-5显示:

    4.4 数据库设计数据库的设计关系到整个应用系统的运行效率,数据库设计得好,不仅有利于日常数据的维护更新,而且可以提高系统的运行效率,缩短数据查询响应周期,增加网站的流量^[9]^。合理的数据库设计可以使围绕它支持的Web页面的Java代码简单化,易于实现,并且可以提高数据存储的效率,保证数据的完整一致。校园二手物品交易系统采用MySQL作为后台数据库开发工具。
    4.4.1 数据库概念设计概念模型用于信息世界的建模,与具体的DBMS无关。为了把现实世界中的具体事物抽象、组织为某一DBMS支持的数据模型。人们常常首先将现实世界抽象为信息世界,然后再将信息世界转换为机器世界。也就是说,首先把现实世界中的客观对象抽象为某一种信息结构,这种信息结构并不依赖于具体的计算机系统和具体的DBMS,而是概念级的模型,然后再把模型转换为计算机上某一个DBMS支持的数据模型。实际上,概念模型是现实世界到机器世界的一个中间层次。
    信息世界中包含的基本概念有实体和联系。

    实体 (entity):客观存在并可相互区别的事物称为实体。实体可以是具体的人、事、物,也可以是抽象的概念或联系。例如,一个学生、一门课、一个供应物、一个部门、一本 书、一位读者等都是实体
    联系 (relationship):在现实世界中,事物内部以及事物之间是有联系的,这些联系在信息世界中反映为实体内部的联系和实体之间的联系。实体内部的联系通常是组成实体的各属性之间的联系。两个实体型之间的联系可以分为3类,一对一联系,(1:1);一对多联系(1 : n);多对多联系(m : n)

    概念模型是对信息世界建模,所以概念模型应该能够方便、准确地表示信息世界中的常用概念。概念模型的表示方法很多,其中最为常用的是P.P.S.Chen于1976年提出的实体,联系方法(Entity-Relationship Approach)简记为E-R表示法)。该方法用E-R图来描述现实世界的概念模型,称为实体-联系模型,简称E-R模型。根据数据流程分析,绘制校园二手物品交易系统的全局E-R模型如图4-6。

    根据系统分析的主要实体有:用户、物品、角色分类、订单、收藏、评论、回复、物品图、一级分类和二级分类。各个实体具体的描述属性图如下(实体属性在下图中并没有全部给出,因为属性过多的原因):
    用户实体

    物品实体

    角色分类实体

    订单实体

    收藏实体

    评论实体

    回复实体

    物品图实体

    一级分类实体

    二级分类实体

    4.4.2数据库逻辑设计数据库逻辑设计主要是把数据库概念设计时设计好的基本E-R图转换为与选用DBMS产品所支持的数据模型相符合的逻辑结构。它包括数据项、记录及记录间的联系、安全性和一致性约束等等。导出的逻辑结构是否与概念模式一致,从功能和性能上是否满足用户的要求,要进行模式评价。
    本系统数据库名称为secondshop,数据库中包括:

    用户表(user_table)
    物品表(good_table)
    角色分类表(role_table)
    订单表(order_table)
    收藏表(collect_table)
    评论表(reply_table)
    回复表(review_table)
    物品图表(image_table)
    一级分类表(first_type_table)
    二级分类表(second_type_table)

    各表数据结构如下:
    用户表(user_table),存储用户信息



    字段名称
    数据类型
    主键
    是否空
    说明




    id
    int
    Y
    N
    用户ID


    name
    varchar
    N
    Y
    用户昵称


    mobile
    varchar
    N
    Y
    手机号


    email
    varchar
    N
    Y
    邮箱


    password
    varchar
    N
    Y
    密码


    code
    varchar
    N
    Y
    用户标签


    photo_url
    varchar
    N
    Y
    头像地址


    role_id
    int
    N
    Y
    角色编号


    gender
    varchar
    N
    Y
    性别


    registr_date
    datetime
    N
    Y
    注册时间


    status_id
    int
    N
    Y
    用户状态ID



    物品表(good_table),存储物品信息



    字段名称
    数据类型
    主键
    是否空
    说明




    id
    int
    Y
    N
    物品ID


    name
    varchar
    N
    Y
    物品名


    photo_url
    varchar
    N
    Y
    物品图片地址


    first_type_id
    int
    N
    Y
    一级分类ID


    second_type_id
    int
    N
    Y
    二级分类ID


    describe
    varchar
    N
    Y
    描述


    upload_date
    datetime
    N
    Y
    发布日期


    prise
    float
    N
    Y
    价格


    status_id
    int
    N
    Y
    物品状态ID


    user_id
    int
    N
    Y
    用户ID


    update
    datetime
    N
    Y
    更新日期



    角色分类表(role_table) ,存储角色分类信息



    字段名称
    数据类型
    主键
    是否空
    说明




    id
    int
    Y
    N
    ID


    code
    varchar
    N
    N
    用户标签


    role
    varchar
    N
    N
    角色



    订单表(order_table) ,存储订单信息



    字段名称
    数据类型
    主键
    是否空
    说明




    id
    int
    Y
    N
    ID


    good_name
    varchar
    N
    Y
    物品名


    seller
    varchar
    N
    Y
    买家


    seller_id
    int
    N
    Y
    卖家ID


    customer
    varchar
    N
    Y
    买家名


    customer_id
    int
    N
    Y
    买家ID


    good_id
    int
    N
    Y
    物品ID


    money
    int
    N
    Y
    价格


    submit_date
    datetime
    N
    Y
    订单提交时间


    end_date
    datetime
    N
    Y
    订单结束时间


    status_id
    int
    N
    Y
    订单状态



    收藏表(collect_table) ,存储收藏信息



    字段名称
    数据类型
    主键
    是否空
    说明




    id
    int
    Y
    N
    ID


    good_id
    int
    N
    Y
    物品ID


    good_name
    varchar
    N
    Y
    物品名称


    user_id
    int
    N
    Y
    用户ID



    评论表(reply_table) ,存储信息



    字段名称
    数据类型
    主键
    是否空
    说明




    id
    int
    Y
    N
    ID


    review_id
    int
    N
    Y
    回复的ID


    from_user
    varchar
    N
    Y
    评论者昵称


    from_user_id
    int
    N
    Y
    评论者ID


    to_user
    varchar
    N
    Y
    回复者昵称


    to_user_id
    int
    N
    Y
    回复者ID


    text
    varchar
    N
    Y
    评论内容


    upload_date
    datetime
    N
    Y
    评论时间


    status
    int
    N
    Y
    评论的状态



    回复表(review_table) ,存储信息



    字段名称
    数据类型
    主键
    是否空
    说明




    id
    int
    Y
    N
    ID


    good_id
    int
    N
    Y
    物品ID


    from_user_id
    int
    N
    Y
    评论者ID


    from_user
    varchar
    N
    Y
    评论者昵称


    to_user_id
    int
    N
    Y
    回复者ID


    to_user
    varchar
    N
    Y
    回复者昵称


    text
    varchar
    N
    Y
    评论内容


    upload_date
    datetime
    N
    Y
    评论时间


    status
    int
    N
    Y
    评论的状态



    物品图表(image_table) ,存储物品图息



    字段名称
    数据类型
    主键
    是否空
    说明




    id
    int
    Y
    N
    ID


    good_id
    int
    N
    Y
    物品ID


    name
    varchar
    N
    Y
    物品名


    url
    varchar
    N
    Y
    地址



    一级分类表(first_type_table) ,存储一级分类信息



    字段名称
    数据类型
    主键
    是否空
    说明




    id
    int
    Y
    N
    ID


    name
    varchar
    N
    Y
    一级分类名



    二级分类表(second_type_table) ,存储二级分类信息



    字段名称
    数据类型
    主键
    是否空
    说明




    id
    int
    Y
    N
    ID


    first_type_id
    int
    N
    Y
    一级分类ID


    name
    varchar
    N
    Y
    分类名



    第五章 校园二手物品交易系统实现本章节介绍了校园二手物品交易系统的实现,包括关键代码、用户模块和管理员模块的实现过程。
    5.1 关键代码本系统使用Maven,pom.xml是配置Maven的,而Maven是整个系统最重要的一部分。它主要是用来用于管理:源代码、配置文件、开发者的信息和角色、问题追踪系统、组织信息、项目授权、项目的url、项目的依赖关系等等。
    pom.xml
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.wzh.secondshop</groupId> <artifactId>wzh-secondshop</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>wzh-secondshop Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <!--Servlet 3.0, EJB Lite 3.1, JPA 2.0, JSP 2.2, EL 1.2, JSTL 1.2, JSF 2.0, JTA 1.1, JSR-45, JSR-250.--> <dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>6.0</version> <scope>provided</scope> </dependency> <!--Spring Core--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.3.RELEASE</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <!--Spring MVC--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.3.RELEASE</version> </dependency> <!--JSTL--> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- Bean Validation --> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.2.4.Final</version> </dependency> <!--MySQL--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.34</version> </dependency> <!--Database Connection Pool--> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <!--MyBatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.0</version> </dependency> <!--MyBatis-Spring--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <!--Spring JDBC--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.3.RELEASE</version> </dependency> <!--Bridge logging from JCL to SLF4j--> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.21</version> </dependency> <!--http://logback.qos.ch/index.html--> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.7</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>RELEASE</version> </dependency> <!--Jackson--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.8.7</version> </dependency> <!--file upload--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> </dependencies> <build> <finalName>wzh-secondshop</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> <showWarnings>true</showWarnings> </configuration> </plugin> </plugins> </build></project>
    注册页面前端jsp代码:register.jsp
    <body style="background-image: url(<c:url value="/statics/image/background/background1.jpg"/>); background-size: cover"> <div class="container" style="margin-top: 30px;"> <div class="row"> <div style="margin: 20px auto; color: #ffffff"> <h1 align="center" ; style="color: #292b33">新用户注册</h1> </div> <div class="col-xs-5 r" style="position: absolute; left: 50%; transform: translateX(-50%); padding: 30px; background-color: #ffffff"> <form:form method="post" commandName="user" items="${user}" id="register"> <spring:bind path="name"> <div class="form-group"> <form:label path="name" cssClass="control-label">姓名</form:label> <form:input path="name" cssClass="form-control" placeholder="请输入姓名"></form:input> </div> </spring:bind> <spring:bind path="gender"> <div class="form-group"> <form:label path="gender" cssClass="control-label">性别</form:label> <form:select path="gender" id="gender" cssClass="form-control"> <form:option value="男">男</form:option> <form:option value="女">女</form:option> </form:select> </div> </spring:bind> <spring:bind path="mobile"> <div class="form-group"> <form:label path="mobile" cssClass="control-label">手机</form:label> <form:input path="mobile" cssClass="form-control" placeholder="请输入手机号码"></form:input> <output itemid="status" style="color: red"></output> </div> </spring:bind> <spring:bind path="email"> <div class="form-group"> <form:label path="email" cssClass="control-label">邮箱</form:label> <form:input path="email" cssClass="form-control" placeholder="请输入邮箱"></form:input> <output itemid="status" style="color: red" value=""></output> </div> </spring:bind> <spring:bind path="password"> <div class="form-group"> <form:label path="password" cssClass="control-label">密码</form:label> <form:input id="p1" path="password" cssClass="form-control" placeholder="请输入密码" type="password"></form:input> </div> </spring:bind> <spring:bind path="password2"> <div class="form-group"> <form:label path="password2" cssClass="control-label">确认密码</form:label> <form:input id="p2" path="password2" cssClass="form-control" placeholder="再次请输入密码" type="password" onblur="checkpass(this)"></form:input> <output id="passError" style="color: red"></output> </div> </spring:bind> <div class="form-group"> <button type="submit" class="btn btn-primary">注册</button> <a class="btn btn-success pull-right" onClick="javascript :history.back(-1);">返回</a> </div> <output style="color: red">${status}</output> </form:form> </div> </div> </div> </div> <script> function checkpass() { var password = document.getElementById("p1"); var passwordConfirm = document.getElementById("p2"); if (password.value != passwordConfirm.value) { document.getElementById("passError").innerHTML = "对不起,您2次输入的密码不一致"; } else { document.getElementById("passError").innerHTML = ""; } } </script> <script src="<c:url value="/statics/jquery-1.12.4/jquery-1.12.4.js"/>"></script> <script src="<c:url value="/statics/bootstrap-3.3.0/js/bootstrap.js"/>"></script> <script src="<c:url value="/statics/jquery-ui-1.12.1/jquery-ui.js"/>"></script> <script src="<c:url value="/statics/jquery-ui-1.12.1/datepicker-zh-CN.js"/>"></script></body>
    处理物品业务逻辑代码:GoodsController.java
    @RequestMapping(value = "/", method = RequestMethod.GET)public String getHomeGoods( ModelMap model, @RequestParam(required = false, defaultValue = "") String searchText, @RequestParam(required = false) Integer secondTypeId, @RequestParam(required = false, defaultValue = "0") int offset, @RequestParam(required = false, defaultValue = "40") int limit) { List<Good> goods = goodService.getGoodsBySearchAndType(searchText, secondTypeId, offset, limit); double goodsNum = goodService.getGoodsBySearchAndTypeCount(searchText, secondTypeId); List<FirstType> firstTypes = typeService.getAllFirstType(); for (FirstType firstType : firstTypes) { firstType.setSecondType(typeService .getSecondTypeByFirstTypeId(firstType.getId())); } model.addAttribute("firstTypes", firstTypes); model.addAttribute("goods", goods); model.addAttribute("pages", Math.ceil(goodsNum / limit)); model.addAttribute("goodsNum", goodsNum); model.addAttribute("offset", offset); model.addAttribute("limit", limit); return "home/homeGoods";}@RequestMapping(value = "/goods/goodInfo", method = RequestMethod.GET)public String getGoodInfo(ModelMap model, HttpSession httpSession, @RequestParam(required = false) Integer goodId) { Good goodInfo = goodService.getGoodById(goodId); if (goodInfo == null) { return "goods/error"; } Integer collect = 1; User user = (User) httpSession.getAttribute("user"); if (user == null) { collect = 0; } else { if (collectService.getCollect(goodId, user.getId())) { collect = 2; } } List<Image> images = imageService.getImageByGoodId(goodId); User goodUser = userService.getUserById(goodInfo.getUserId()); goodInfo.setGoodUser(userService.getUserById(goodInfo.getUserId())); goodInfo.setGoodSecondType(typeService.getSecondTypeById(goodInfo .getSecondTypeId())); List<Review> reviews = reviewService.gerReviewByGoodId(goodId); for (Review review : reviews) { review.setReplys(reviewService.gerReplyByReviewId(review.getId())); } List<Good> goods = goodService.getRECGoods(goodInfo.getSecondTypeId(), goodInfo.getId()); model.addAttribute("message", message); model.addAttribute("reviews", reviews); model.addAttribute("goodInfo", goodInfo); model.addAttribute("images", images); model.addAttribute("goodUser", goodUser); model.addAttribute("goods", goods); model.addAttribute("collect", collect); message = ""; return "goods/goodInfo";}@RequestMapping(value = "/goods/goodInfo", method = RequestMethod.POST)public String putReview( @RequestParam(value = "goodId", required = false) Integer goodId, @RequestParam(value = "reviewId", required = false) Integer reviewId, @RequestParam(value = "fromUserId", required = false) Integer fromUserId, @RequestParam(value = "toUserId", required = false) Integer toUserId, @RequestParam(value = "fromUser", required = false) String fromUser, @RequestParam(value = "toUser", required = false) String toUser, @RequestParam(value = "replyText", required = false, defaultValue = "") String replyText, @RequestParam(value = "reviewText", required = false, defaultValue = "") String reviewText) { if (reviewText.equals("")) { if (replyText.equals("")) { message = "内容不能为空!"; return "redirect:/goods/goodInfo?goodId=" + goodId; } else { Reply reply = new Reply(); reply.setReviewId(reviewId); reply.setFromUser(fromUser); reply.setFromUserId(fromUserId); reply.setToUser(toUser); reply.setToUserId(toUserId); reply.setText(replyText); if (reviewService.insertReply(reply) == 1) { message = "回复成功!"; return "redirect:/goods/goodInfo?goodId=" + goodId; } else { message = "回复失败!"; return "redirect:/goods/goodInfo?goodId=" + goodId; } } } else { Review review = new Review(); review.setGoodId(goodId); review.setFromUser(fromUser); review.setFromUserId(fromUserId); review.setToUserId(toUserId); review.setText(reviewText); if (reviewService.insertReview(review) == 1) { message = "评论成功!"; return "redirect:/goods/goodInfo?goodId=" + goodId; } else { message = "评论失败!"; return "redirect:/goods/goodInfo?goodId=" + goodId; } }}@RequestMapping(value = "/goods/publishGood", method = RequestMethod.GET)public String getPublishGood(ModelMap model, HttpSession session) { User user = (User) session.getAttribute("user"); if (user == null) { return "redirect:/"; } Good good = new Good(); List<FirstType> firstTypes = typeService.getAllFirstType(); List<Good> goods = goodService.getAllGoods(0, 5); model.addAttribute("goods", goods); model.addAttribute("good", good); model.addAttribute("firstTypes", firstTypes); return "goods/publishGood";}@RequestMapping(value = "/goods/publishGood", method = RequestMethod.POST)public String getGoodId(ModelMap model, HttpSession session, @Valid Good good) { List<FirstType> firstTypes = typeService.getAllFirstType(); User user = (User) session.getAttribute("user"); List<Good> goods = goodService.getAllGoods(0, 5); good.setUserId(user.getId()); good.setPhotoUrl("/statics/image/goods/default/nophoto.png"); if (goodService.insertGood(good) != 1) { System.out.println("插入物品失败!"); } model.addAttribute("goods", goods); model.addAttribute("good", good); model.addAttribute("firstTypes", firstTypes); return "goods/publishGood";}@RequestMapping(value = "/goods/publishGood/uploadImage", method = RequestMethod.POST)public String uploadImage( HttpSession session, @RequestParam(value = "goodId", required = false) Integer goodId, @RequestParam(value = "mainFile", required = false) MultipartFile mainFile, @RequestParam(value = "file", required = false) MultipartFile[] file) throws IOException { User user = (User) session.getAttribute("user"); FileCheck fileCheck = new FileCheck(); RandomString randomString = new RandomString(); String filePath = "/statics/image/goods/" + user.getId() + "/" + goodId; String pathRoot = fileCheck.checkGoodFolderExist(filePath); String name; if (!mainFile.isEmpty()) { String fileName = goodId + randomString.getRandomString(10); String contentType = mainFile.getContentType(); String imageName = contentType .substring(contentType.indexOf("/") + 1); name = fileName + "." + imageName; mainFile.transferTo(new File(pathRoot + name)); String photoUrl = filePath + "/" + name; goodService.updateGoodPhotoUrl(photoUrl, goodId); } for (MultipartFile mf : file) { if (!mf.isEmpty()) { // 生成uuid作为文件名称 String fileName = goodId + randomString.getRandomString(10); // 获得文件类型(可以判断如果不是图片,禁止上传) String contentType = mf.getContentType(); // 获得文件后缀名称 String imageName = contentType.substring(contentType .indexOf("/") + 1); name = fileName + "." + imageName; System.out.println("name:" + name); mf.transferTo(new File(pathRoot + name)); Image image = new Image(); image.setGoodId(goodId); image.setName(name); image.setUrl(filePath + "/" + name); imageService.insertImage(image); } else { System.out.println("文件为空!"); } } return "redirect:/goods/goodInfo?goodId=" + goodId;}@RequestMapping(value = "/goods/userGoods", method = RequestMethod.GET)public String getUserGoods(ModelMap model, @RequestParam(value = "userId", required = false) Integer userId) { User user = userService.getUserById(userId); List<Good> userGoods = goodService.getGoodStatusByUserId(userId); List<Good> goods = goodService.getAllGoods(0, 4); model.addAttribute("user", user); model.addAttribute("userGoods", userGoods); model.addAttribute("goods", goods); return "goods/userGood";}@RequestMapping(value = "/goods/userGoodEdit", method = RequestMethod.GET)public String getUserGoodEdit(ModelMap model, @RequestParam(value = "goodId", required = false) Integer goodId, HttpSession session) { User user = (User) session.getAttribute("user"); if (user == null) { return "redirect:/"; } Good good = goodService.getGoodById(goodId); List<FirstType> firstTypes = typeService.getAllFirstType(); List<Good> goods = goodService.getAllGoods(0, 5); List<Image> goodImages = imageService.getImageByGoodId(goodId); model.addAttribute("goods", goods); model.addAttribute("good", good); model.addAttribute("goodImages", goodImages); model.addAttribute("firstTypes", firstTypes); return "goods/userGoodEdit";}@RequestMapping(value = "/goods/userGoodEdit", method = RequestMethod.POST)public String postGoodEdit(ModelMap model, HttpSession session, @Valid Good good) { List<FirstType> firstTypes = typeService.getAllFirstType(); User user = (User) session.getAttribute("user"); if (user == null) { return "redirect:/"; } List<Good> goods = goodService.getAllGoods(0, 5); if (!(goodService.updateGood(good) > 0)) { System.out.println("修改物品失败!"); } List<Image> goodImages = imageService.getImageByGoodId(good.getId()); model.addAttribute("goods", goods); model.addAttribute("good", good); model.addAttribute("goodImages", goodImages); model.addAttribute("firstTypes", firstTypes); return "goods/userGoodEdit";}@RequestMapping(value = "/goods/userGoodEdit/updateImage", method = RequestMethod.POST)public String updateImage( HttpSession session, @RequestParam(value = "goodId", required = false) Integer goodId, @RequestParam(value = "mainFile", required = false) MultipartFile mainFile, @RequestParam(value = "file", required = false) MultipartFile[] file) throws IOException { User user = (User) session.getAttribute("user"); FileCheck fileCheck = new FileCheck(); imageService.deleteImage(goodId); RandomString randomString = new RandomString(); String filePath = "/statics/image/goods/" + user.getId() + "/" + goodId; String pathRoot = fileCheck.checkGoodFolderExist(filePath); String name; if (!mainFile.isEmpty()) { String contentType = mainFile.getContentType(); String fileName = goodId + randomString.getRandomString(10); String imageName = contentType .substring(contentType.indexOf("/") + 1); name = fileName + "." + imageName; mainFile.transferTo(new File(pathRoot + name)); String photoUrl = filePath + "/" + name; goodService.updateGoodPhotoUrl(photoUrl, goodId); } for (MultipartFile mf : file) { if (!mf.isEmpty()) { String contentType = mf.getContentType(); String fileName = goodId + randomString.getRandomString(10); String imageName = contentType.substring(contentType .indexOf("/") + 1); name = fileName + "." + imageName; System.out.println("name:" + name); mf.transferTo(new File(pathRoot + name)); Image image = new Image(); image.setGoodId(goodId); image.setName(name); image.setUrl(filePath + "/" + name); imageService.insertImage(image); } } return "redirect:/goods/goodInfo?goodId=" + goodId;}@RequestMapping(value = "/goods/userGoodEdit/delete/{goodId}", method = RequestMethod.GET)public ResponseEntity deleteGood(@PathVariable Integer goodId) { Boolean success; success = goodService.deleteGood(goodId) > 0; return ResponseEntity.ok(success);}@RequestMapping(value = "/goods/userGoodEdit/updateGoodStatus/{goodId}", method = RequestMethod.GET)public ResponseEntity updateGoodStatus(@PathVariable Integer goodId) { Boolean success; success = goodService.updateGoodStatusId(0, goodId) > 0; return ResponseEntity.ok(success);}@RequestMapping(value = "/admin/goods/allGoods", method = RequestMethod.GET)public ResponseEntity adminGetAllGoods() { List<Good> goodList = goodService.getAllGoodList(); for (Good good : goodList) { good.setGoodUser(userService.getUserById(good.getUserId())); good.setGoodSecondType(typeService.getSecondTypeById(good .getSecondTypeId())); } return ResponseEntity.ok(goodList);}
    5.2 用户模块5.2.1 首页用户进行系统,系统首页展示如下:

    5.2.2 物品分类显示物品分类,用户选择图书一级分类,显示二级分类,点击小说分类并显示有关小说的物品。

    5.2.3注册登录用户填写姓名、性别,手机、邮箱和密码就能注册成为本系统的用户了。

    用户输入邮箱和密码,点击登录,即可登陆系统。

    5.2.4 物品详情显示物品详情,这种情况是用户未登录状态,用户不能购买、联系卖家和留言。


    显示物品详情,用户已经登录,用户可以收藏和评论物品或者购买物品。


    5.2.5 发布主页用户登录成功后可点击发布,进入发布主页,进行发布物品操作。


    5.2.6 我的主页用户登录成功后可点击我的,进入我的主页,可以进行个人信息的修改,查看收藏的物品、发布物品、卖出的物品、收到的评论、收到的回复和所有订单。



    5.3 管理员模块5.3.1 管理员登录系统后台登录,管理员输入账号和密码登录后台。

    登录后台后,界面如下:

    5.3.2 物品分类管理系统管理员可以添加一级分类和二级分类,删除一级分类和二级分类。

    5.3.3 物品管理系统管理员可以对物品进行下架和删除操作。

    5.3.4 订单管理系统管理员可以对订单删除操作。

    5.3.5 用户管理系统管理员可以对用户进行禁用和删除操作。

    第六章 系统测试6.1 测试的目的与目标在校园二手物品交易系统进行初步实现之后,开始进行对系统进行测试,找出系统中存在的Bug,通过测试,用提交的Bug报告来为以后软件的改进提供标准和参考,能够在以后的系统改进中找到依据。
    测试后的软件各模块基本功能可以顺利进行,尽可能的提高软件的健壮性。
    6.2 测试方法
    从是否关心软件内部结构和具体实现的角度划分:黑盒测试和白盒测试
    从是否执行程序的角度:静态测试和动态测试
    从软件开发的过程按阶段划分有:单元测试、集成测试、确认测试、系统测试、验收测试、回归测试、Alpha测试、Beta测试

    单元测试又称模块测试,是针对软件设计的最小单位 ─ 程序模块(这里所说的程序模块在Java中一个模块就是一个方法),进行正确性检验的测试工作。其目的在于发现各模块内部可能存在的各种差错。单元测试需要从程序的内部结构出发设计测试用例。多个模块可以平行地独立进行单元测试。
    集成测试 (组装测试、联合测试),通常在单元测试的基础上,需要将所有模块按照设计要求组装成为系统。这时需要考虑的问题是:

    在把各个模块连接起来的时候,穿越模块接口的数据是否会丢失
    一个模块的功能是否会对另一个模块的功能产生不利的影响
    各个子功能组合起来,能否达到预期要求的父功能
    全局数据结构是否有问题
    单个模块的误差累积起来,是否会放大,从而达到不能接受的程度

    确认测试(Validation Testing),确认测试又称有效性测试。任务是验证软件的功能和性能及其它特性是否与用户的要求一致。对软件的功能和性能要求在软件需求规格说明书中已经明确规定。它包含的信息就是软件确认测试的基础。
    系统测试(System Testing),是将通过确认测试的软件,作为整个基于计算机系统的一个元素,与计算机硬件、外设、某些支持软件、数据和人员等其它系统元素结合在一起,在实际运行环境下,对计算机系统进行一系列的组装测试和确认测试。系统测试的目的在于通过与系统的需求定义作比较, 发现软件与系统的定义不符合或与之矛盾的地方。
    验收测试(Acceptance Testing),在通过了系统的有效性测试及软件配置审查之后,就应开始系统的验收测试。验收测试是以用户为主的测试。软件开发人员和QA(质量保证)人员也应参加。由用户参加设计测试用例,使用生产中的实际数据进行测试。在测试过程中,除了考虑软件的功能和性能外,还应对软件的可移植性、兼容性、可维护性、错误的恢复功能等进行确认。
    6.3 测试用例由于功能模块较多,测试内容篇幅较长,所以在本论文中只介绍登入系统的测试用例,表6.1是本系统用户登入的测试表,从测试的结果来看与期望结果完全相同。
    登录系统测试用例



    功能特性
    用户登录验证








    测试目的
    验证是否输入合法的信息






    测试数据
    邮箱:1111 密码:1111






    测试内容
    操作描述
    数据
    期望结果
    实际结果
    测试状态


    1
    输入邮箱,按“登陆”按钮。
    邮箱为:1111,密码为空
    显示警告信息“邮箱或密码错误!”
    显示警告信息“邮箱或密码误!”
    与期望结果相同


    2
    输入密码,按“登陆”按钮。
    邮箱为:空,密码为:1111
    显示警告信息“邮箱或密码错误!”
    显示警告信息“邮箱或密码错误!”
    与期望结果相同


    3
    输入邮箱和密码,按“登陆”按钮。
    邮箱为:1111,密码为:1111
    显示警告信息“邮箱或密码错误!”
    显示警告信息“邮箱或密码错误”
    与期望结果相同


    4
    输入邮箱和密码,按“登录”按钮。
    邮箱为:1111,密码为:1111
    正确登入到用户操作界面
    正确登入到用户操作界面
    与期望结果相同



    6.4 测试结论把开始的代码写得越好,它出现的错误也就越少,你也就越能相信所做过的测试是彻底的。系统化测试以一种有序方式设法探测潜在的麻烦位置。同样,毛病最可能出现在边界,这可以通过手工的或者程序的方式检查。自动进行测试是最理想的,用得越多越好,因为机器不会犯错误、不会疲劳、不会用臆想某此实际无法工作的东西能行来欺骗自己。回归测试检查一个程序是否能产生与它们过去相同的输出。在做了小改变之后就测试是一种好技术, 能帮助我们将出现问题的范围局部化,因为新问题一般就出现在新代码里面。
    测试和排错常常被说成是一个阶段,实际上它们根本不是同一件事。简单地说,排错是在你已经知道程序有问题时要做的事情。而测试则是在你在认为程序能工作的情况下,排错是在你已经知道程序有问题时要做的事情。而测试则是在你在认为程序能工作的情况下,为设法打败它而进行的一整套确定的系统化的试验。
    Edsger Dijkstra有一个非常有名的说法:测试能够说明程序中有错误,但却不能说明其中没有错误。他的希望是,程序可以通过某种构造过程正确地做出来,这样就不再会有错误了,因此测试也就不必要了。这确实是个美好生活的目标,但是,对今天的实际程序而言,这仍然还只是一个理想。所以应该集中精力讨论如何测试,如何才能够更快地发现程序错误,如何才可以使得工作更有成效、效率更高。
    结论与展望设计开发基于 Jsp+SSM+MySql+Maven框架的校园二手物品交易系统是集业务管理与软件技术为一身的工作,只有在理解业务的基础上,才能对业务操作流程进行提炼优化,并通过软件设计与开发技术实现。本文设计的校园二手物品交易系统界面友好、功能丰富、操作简单,能适应大部分环境下的校园二手网络交易所需要的工作。本系统在设计采用了 J2EE 框架,设计上实现了高内聚、低耦合的要求,在设计上做到了可扩张和维护。本文在论文撰写、系统开发时对现有二手物品交易系统做了深入的调研,并行性了需求分析和系统设计,最终实现了一个实用的网上校园二手物品交易系统。
    通过开发《校园二手物品交易系统》,我较为全面的掌握了JAVA的基本知识和编程技巧,并在开发过程中我的JAVA开发能力得到了进一步的提高。如:更进一步的深入了解MVC设计模式,软件三层框架;SQL语言的使用。
    在开发过程中我学到了一些经验:系统分析的好坏将决定着的系统开发成功与否,一份好分析设计将是成功开发主要因素。我们在着手开发之前不要急于编程,先应有较长的时间去把分析做好,做好数据库设计工作,写出相关的开发文档等。然后再开始编写程序代码,这样做到每段代码心底都有数,有条不紊。当然也有些还需待继续深入地方如:控件的应用等。
    此外,我们还觉得,我们个人在这次设计中走了很多弯路。主要是因为平时很少接触软件开发工作,在应用方面缺乏经验,以后还需要更多的努力。
    对我们来说,这次设计的本身所产生的影响,还远远没有结束,我们从本次毕业设计中学到了许多课本上没有的知识。通过自己的学习和努力;通过老师的指导和教育,使我们不仅仅在知识水平和解决实际问题的能力上有了很大的提高。还从思想的深处体会到,要把自己的所学变成现实时所将面对的种种难题。
    0  留言 2021-09-22 11:30:30
  • 基于Springboot和Freemarker实现的校园二手市场网站

    1.项目简介1.1 项目背景如今的大学校园中 随着大学生的购买能力的提高存在着两种局面。一是大学期间购买的收纳类、实用类物品,在毕业季大家面临带不走、不舍得扔的尴尬局面;二是购买的东西中越来越多的大家用不上的物品,这些物品成了大部分大学生的累赘。因此,低价卖掉这些仍可以继续利用的物品是一个两全其美的方法于是校园二手交易市场诞生了。随着科技的迅速发展校园二手商品交易市场也不仅仅局限于校园内摆地摊的形式,大家更多的是使用手机线上购物,我们的项目就是基于这样的局面产生的,让同学们足不出户就可以淘到自己所需要的物美价廉的物品。
    校园现状:

    开学季大量涌入的新生他们需要购置生活用品,学习材料,学习用品等,形成了大量购物的需求狂潮
    毕业季老生离校带不走的生活用品,带不走的学习材料,形成了大量的浪费,令人可惜
    平日需求里,由于大学生喜好买东西,闲置下来的东西,累积下来是个负担,需要置换来各取所需
    开学季、毕业季校园出现大量的学生自发起的购物小摊,给校园带来了拥挤,不便管理等安全隐患,也带来了不好的校园风气

    1.2 系统概述校园二手交易网为用户提供了一个二手交易的平台。根据大中学校商品情况及学生的实际需求,系统的主要功能模块为信息分类、信息搜索、发布信息、用户注册登陆、管理后台等。在网站的设计中,分为前台和后台两个部分设计,前台主要用于提供用户注册和登陆、发布供求信息、查询供求信息、用户留言等功能,后台主要功能有用户管理、供求信息管理、信息分类管理、留言管理等。系统还可提供用户对自己发表的供求信息的删除,以及对用户信息的修改功能,可以方便用户对自己基本信息的管理。
    学校二手交易平台的优点:

    提供创业条件,大学生创业项目规模小、竞争能力弱、资金实力不足,在保证合理学习的同时,还能勤工俭学
    校园环境优化,在不影响大学生自主买卖,置换购物的同时,优化校园环境,给校园带来更好的管理
    响应国家、学校号召,构建校园二手交易市场不仅有利于“节能减排”,符合国家的绿色发展要求和可持续发展要求,为卖家学生和买家学生提供了完美结合的平台。二手交易市场的建立是对当前形势的响应,体现了可持续发展的节约理念和绿色的环保理念,是建立节约型社会的方针政策

    1.3 系统功能描述
    系统的使用者为系统管理员和用户,用户在系统注册后生成用户信息表文件。系统的功能分为两个模块,面向管理员的模块功能是系统管理,主要是删除系统非法用户的帐号信息;面向一般用户的模块功能是户信息管理和交易管理。其中,用户信息管理包括更改用户注册邮箱,更改用户密码,更改用户基本信息;交易管理包括出售管理,求购管理,买卖信息管理。
    系统管理

    管理员功能:对用户发出警告,从用户信息表中删除非法用户,这项功能只能为管理员所有。
    用户管理

    这个模块实现了用户请求交易,发布、更新交易信息的功能,并使用户能够更新自己的注册信息以及基本信息。
    交易管理

    在用户交易管理中,根据用户的提供的交易物品生成了“出售信息表”和“求购信息表”,用户可以随时对自发布的信息进行更改或删除。在交易的过程中,系统会根据这两个表生成对应物品的求购(出售)信息目录供用户浏览参考。对于没有明显求购或出售目标的用户,也可以浏览由求购、出售信息表生成的求购、出售物品目录。
    订单管理

    用户录入出售信息(包括出售物品名称,出售物品价格,出售物品种类,出售物品简单描述,联系电话,电子邮箱)。经用户检查录入信息正确无误,生成出售物品信息单。系统将出售信息纳入出售信息表,并根据出售信息表上的内容发布出售信息。
    买卖信息更新管理

    用户可以随时更改买卖信息。
    搜索

    2.数据库设计2.1 表结构分类表

    留言表

    商品表

    菜单表

    日志表

    公告表

    权限表

    系统设置表

    学生表

    管理员表

    2.2 E-R图
    3.系统设计/** * 系统统一的图片查看方法 * @param filename * @return */ @GetMapping(value="/view") public ResponseEntity viewPhoto(@RequestParam(name="filename",required=true)String filename){ Resource resource = resourceLoader.getResource("file:" + photoConfig.getUploadPhotoPath() + filename); try { return ResponseEntity.ok(resource); } catch (Exception e) { return ResponseEntity.notFound().build(); } } @PostMapping(value = "upload_photo") public Result<String> upload_photo(@RequestParam("photo")MultipartFile photo){ //获取图片的名称 String originalFilename= photo.getOriginalFilename(); //获取图片的后缀 String suffix=originalFilename.substring(originalFilename.lastIndexOf("."),originalFilename.length()); //图片格式不正确 if(!photoConfig.getUploadPhotoSuffix().contains(suffix.toLowerCase())){ return Result.exception(CodeMsg.UPLOAD_PHOTO_SUFFIX_ERROR); } if((photo.getSize()/1024)>photoConfig.getUploadPhotoMaxSize()){ CodeMsg codeMsg=CodeMsg.UPLOAD_PHOTO_ERROR; codeMsg.setMsg("图片大小不能大于"+photoConfig.getUploadPhotoMaxSize()+"M"); return Result.exception(codeMsg); } File file = new File(photoConfig.getUploadPhotoPath()); //判断文件夹是否存在 if(!file.exists()){ file.mkdir(); } file=new File(photoConfig.getUploadPhotoPath()+ StringUtil.dataFormat(new Date(),"yyyyMMdd" )); if(!file.exists()){ file.mkdir(); } String filename=StringUtil.dataFormat(new Date(),"yyyyMMdd" )+"/"+System.currentTimeMillis()+suffix; file=new File(photoConfig.getUploadPhotoPath()+filename); try { photo.transferTo(file); } catch (IOException e) { e.printStackTrace(); } logger.info(originalFilename+"图片上传成功"); return Result.success(filename); }}
    @GetMapping(value="/generate_cpacha")public void generateCpacha( @RequestParam(name="vl",defaultValue="4")Integer vcodeLength,//vcodeLength,验证码长度 @RequestParam(name="fs",defaultValue="21")Integer fontSize,//fontSize,验证码字体大小 @RequestParam(name="w",defaultValue="98")Integer width,//width,图片宽度 @RequestParam(name="h",defaultValue="33")Integer height,//height,图片高度 @RequestParam(name="method",defaultValue="admin_login")String method,//用来调用此方法的名称,以此名称为键,存入到session中 HttpServletRequest request, HttpServletResponse response){ CpachaUtil cpachaUtil = new CpachaUtil(vcodeLength,fontSize,width,height); String generatorVCode = cpachaUtil.generatorVCode(); //将生成的验证码放入session,以供放后面程序的验证使用 request.getSession().setAttribute(method, generatorVCode); log.info("验证码成功生成,验证码id=" + method + ",验证码为=" + generatorVCode); try { ImageIO.write(cpachaUtil.generatorRotateVCodeImage(generatorVCode, true), "gif", response.getOutputStream()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }}
    4.项目实现4.1 用户界面首页

    登录/注册

    分类


    搜索

    商品详情

    联系商家

    评论

    卖东西

    用户中心

    4.2 管理员页面登录

    首页

    菜单管理

    角色管理

    管理员管理

    分类管理

    商品管理

    学生用户管理

    留言管理

    公告管理

    系统设置

    5.总结在如今互联网时代,电子商务方便了我们的生活,在“买买买”时代的大背景下,尤其是当今大学生占比重的大头,他们会一时兴起买自己喜欢的东西,可是一段时间后又没有了当初的热爱。物品的价值便慢慢流逝了,为了帮助大学生随时随地处理自己的旧物品,发挥其剩余价值,我们校园跳蚤市场交易系统便诞生了。本系统最终满足了大部分用户的需求,做到了随时随地交易的目标。为了促进“可持续发展经济”的目标,本系统旨在打造“最人性化”、“最环保”、“最节约”的交易功能模式。
    本系统在设计实现的过程中遇到了很多的问题,比如:对于系统设计方案的取舍、界面功能的重叠、获取数据后解析数据包失败等等。以下简短列出几个问题:
    系统的设计方案
    在设计之初,选择了订单和商品复用同一个界面,但是限制就比较大,订单和商品的共同点相对较少,对系统核心功能实现有点影响。
    解决方案:参照市面上现有的应用程序——淘宝,将订单和商品分开,进入不同的界面根据两个实体类不同的属性,进行相关操作,极大地扩展到系统的功能,是用户运用起来更灵活。
    客户端界面设计
    后期在APP的界面、美工方面投入了大量时间精力,参考了很多APP的设计风格,从零开始弄得很花哨,不适合大众的审美。
    解决方案:本着一应从简的原则,取消了繁杂的界面图片,改用烟灰白、白色、黑色搭配的简约界面设计。如此一来,尽管在美观性上略有欠缺,但是功能更加直观,让用户能够在尽量少的时间内发布信息、达成所需,给用户带来了更好使用体验。
    校园跳蚤市场交易系统的设计与实现已全部完成,可以顺利的运行并完成基础的应用。对于后续的版本,本系统在确保核心功能不变的情况下,可以添加留下的未实现的功能,为系统增添多样化元素;可以继续完善界面布局和功能分配,减少功能耦合,优化数据库的表结构,提高服务器性能,增大并发线程数,以期给用户带来更好的使用体验。
    0  留言 2021-09-22 11:15:14
  • 基于springboot和mysql实现的人事管理系统

    一、系统介绍1.1项目简介本系统为人事管理系统,系统分为七大模块:绩效考核,招聘管理,档案管理,工资管理,考勤管理,培训管理,系统管理。
    可满足小企业日常办公。本系统最大特色是有强大和灵活的权限控制功能,所有菜单,按钮功能均可由管理通过配置来控制。
    系统默认有四个角色:管理员,财务专员,人事专员,普通用户

    管理员(admin/admin):可以操作所有功能
    财务专员(cw/cw):可查看工资管理,考勤管理,培训管理等内容
    人事专员(rs/rs):可查看和管理招聘管理,档案管理,培训管理等内容
    普通用户(wdc/wdc):只可查看工资,打卡考勤,参加培训等

    1.2背景分析今年以来,因为疫情导致很多企业发展遇到了不少难题,尤其是中小企业,常常会出现流程不完善,管理方式单一,缺少有效的人才培养方式,工作效率难以提高的问题,本来今年生意就不好做了,如果再遇到这些问题,很有可能就造成企业入不敷出,难以经营延续。那么怎么才能解决上述问题呢?
    其实,你离解决问题可能就差一款合适你企业的人事管理系统。
    一、人事管理系统是什么?人事管理系统,简单的讲就是结合企业先进的人力资源实践或理念、人力资源资源信息化建设的建设,通过信息技术手段为企业提供人力资源解决方案。能直接把HR从繁琐的基础工作中解放出来,还可以提高人事管理的精准率,使HR更加轻松快捷地完成工资管理的任务。
    二、人事管理系统有什么优势?1、 人事管理系统最明显的优势就是提升工作效率。系统可以根据企业的需求自动生成管理方案,做到人力资源自动化管理,大大提高工作效率。2、 企业可以根据系统随时掌握企业人员信息,及时合理的分配人才。3、 系统可以提供实时监控,明确收入产出情况,提高市场适应能力。4、 系统的执行可以支撑企业的战略决策,为企业发展提供数据支撑。5、 借助系统可以明确企业结构,更好的掌控成本。
    1.3软件架构基础环境:

    JDK:1.8MySQL:5.7Maven3.0
    使用框架:

    核心框架:Spring Boot 2.1.8.RELEASE视图框架:Spring MVC 5.0ORM框架:MyBatisPlus 3.1.2数据库连接池:Druid 1.1安全框架:Apache Shiro 1.4日志:SLF4J 1.7、Log4j前端框架:Layui,ztree,jquery,bootstrap
    1.4功能模块总体结构设计

    用例图

    系统管理员实现的功能:

    人事管理员

    系统功能介绍
    用户管理的功能包括:添加用户,用户可以为管理员或者普通用户;查询用户,可以查询所有用户或根据用户名和用户状态进行模糊查
    询,删除用户,修改用户。
    部门管理的功能包括:添加部门,查询部门,可以查询所有部门或根据部门名称进行模糊查询,删除部门,修改部门 职位管理的功能包
    括:添加职位,查询职位,可以查询所有职位或根据职位名称进行模糊查询,删除职位,修改职位
    员工管理的功能包括:添加员工,查询员工,可以查询所有员工或根据员工姓名,身份证号,手机号,性别,职位,部门进行模查询,删
    除员工,修改员工。
    公告管理的功能包括:添加公告,查询公告,可以查询所有公告或根据公告名称,公告内容进行模糊查询,删除公告,修改公告。
    1.5开发思路在开发的过程中最主要的部分就是对ssm的整体实现,主要分为以下四个模块:

    dao层,实现数据库的访问1)mapper.xml文件,在其中写sql语句,对应数据库中的操作,定义需要实现的功能,如insert、select、update2)mapper.java接口,将mapper.xml中的操作按照id映射成java函数service层,业务层1)写service.java接口,为控制层提供服务,并写serviceImpl.java在其中自动装配mapper,完成相应功能并返回给控制层controller,实现具体的事务控制1)写controller.java,连接页面请求和服务层,获取页面请求的参数,通过service的自动装配,映射不同的URL到相应到不同的地方处理函数,并获取参数,对参数处理返回给服务层
    二.数据库设计2.1系统数据流图
    2.2ER图
    三、项目开发1、项目配置spring: datasource: type: com.alibaba.druid.pool.DruidDataSource druid: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/person_system?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai username: root password: 123456 initial-size: 10 max-active: 100 min-idle: 10 max-wait: 60000 pool-prepared-statements: true max-pool-prepared-statement-per-connection-size: 20 time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000 #Oracle需要打开注释 #validation-query: SELECT 1 FROM DUAL test-while-idle: true test-on-borrow: false test-on-return: false stat-view-servlet: enabled: true url-pattern: /druid/* #login-username: admin #login-password: admin filter: stat: log-slow-sql: true slow-sql-millis: 1000 merge-sql: false wall: config: multi-statement-allow: true
    2.过滤器配置@Configurationpublic class FilterConfig { @Bean public FilterRegistrationBean shiroFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new DelegatingFilterProxy("shiroFilter")); //该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 registration.addInitParameter("targetFilterLifecycle", "true"); registration.setEnabled(true); registration.setOrder(Integer.MAX_VALUE - 1); registration.addUrlPatterns("/*"); return registration; } @Bean public FilterRegistrationBean xssFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setDispatcherTypes(DispatcherType.REQUEST); registration.setFilter(new XssFilter()); registration.addUrlPatterns("/*"); registration.setName("xssFilter"); registration.setOrder(Integer.MAX_VALUE); return registration; }}
    3.安全框架shiro配置@Configurationpublic class ShiroConfig { /** * 单机环境,session交给shiro管理 */ @Bean @ConditionalOnProperty(prefix = "person", name = "cluster", havingValue = "false") public DefaultWebSessionManager sessionManager(@Value("${person.globalSessionTimeout:3600}") long globalSessionTimeout){ DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); sessionManager.setSessionValidationSchedulerEnabled(true); sessionManager.setSessionIdUrlRewritingEnabled(false); sessionManager.setSessionValidationInterval(globalSessionTimeout * 1000); sessionManager.setGlobalSessionTimeout(globalSessionTimeout * 1000); return sessionManager; } /** * 集群环境,session交给spring-session管理 */ @Bean @ConditionalOnProperty(prefix = "person", name = "cluster", havingValue = "true") public ServletContainerSessionManager servletContainerSessionManager() { return new ServletContainerSessionManager(); } @Bean("securityManager") public SecurityManager securityManager(UserRealm userRealm, SessionManager sessionManager) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(userRealm); securityManager.setSessionManager(sessionManager); securityManager.setRememberMeManager(null); return securityManager; } @Bean("shiroFilter") public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); shiroFilter.setSecurityManager(securityManager); shiroFilter.setLoginUrl("/login.html"); shiroFilter.setUnauthorizedUrl("/"); Map<String, String> filterMap = new LinkedHashMap<>(); filterMap.put("/v2/api-docs", "anon"); filterMap.put("/webjars/**", "anon"); filterMap.put("/statics/**", "anon"); filterMap.put("/login.html", "anon"); filterMap.put("/sys/login", "anon"); filterMap.put("/favicon.ico", "anon"); filterMap.put("/captcha.jpg", "anon"); filterMap.put("/**", "authc"); shiroFilter.setFilterChainDefinitionMap(filterMap); return shiroFilter; } @Bean("lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; }
    4.常用工具类日期工具类
    /** 时间格式(yyyy-MM-dd) */public final static String DATE_PATTERN = "yyyy-MM-dd";/** 时间格式(yyyy-MM-dd HH:mm:ss) */public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; /** * 日期格式化 日期格式为:yyyy-MM-dd * @param date 日期 * @return 返回yyyy-MM-dd格式日期 */public static String format(Date date) { return format(date, DATE_PATTERN); }public static String currentTimeFormat() { return format(new Date(), DATE_TIME_PATTERN); } /** * 日期格式化 日期格式为:yyyy-MM-dd * @param date 日期 * @param pattern 格式,如:DateUtils.DATE_TIME_PATTERN * @return 返回yyyy-MM-dd格式日期 */ public static String format(Date date, String pattern) { if(date != null){ SimpleDateFormat df = new SimpleDateFormat(pattern); return df.format(date); } return null; } /** * 字符串转换成日期 * @param strDate 日期字符串 * @param pattern 日期的格式,如:DateUtils.DATE_TIME_PATTERN */ public static Date stringToDate(String strDate, String pattern) { if (StringUtils.isBlank(strDate)){ return null; } DateTimeFormatter fmt = DateTimeFormat.forPattern(pattern); return fmt.parseLocalDateTime(strDate).toDate(); } /** * 根据周数,获取开始日期、结束日期 * @param week 周期 0本周,-1上周,-2上上周,1下周,2下下周 * @return 返回date[0]开始日期、date[1]结束日期 */ public static Date[] getWeekStartAndEnd(int week) { DateTime dateTime = new DateTime(); LocalDate date = new LocalDate(dateTime.plusWeeks(week)); date = date.dayOfWeek().withMinimumValue(); Date beginDate = date.toDate(); Date endDate = date.plusDays(6).toDate(); return new Date[]{beginDate, endDate}; } /** * 对日期的【秒】进行加/减 * * @param date 日期 * @param seconds 秒数,负数为减 * @return 加/减几秒后的日期 */ public static Date addDateSeconds(Date date, int seconds) { DateTime dateTime = new DateTime(date); return dateTime.plusSeconds(seconds).toDate(); } /** * 对日期的【分钟】进行加/减 * * @param date 日期 * @param minutes 分钟数,负数为减 * @return 加/减几分钟后的日期 */ public static Date addDateMinutes(Date date, int minutes) { DateTime dateTime = new DateTime(date); return dateTime.plusMinutes(minutes).toDate(); } /** * 对日期的【小时】进行加/减 * * @param date 日期 * @param hours 小时数,负数为减 * @return 加/减几小时后的日期 */ public static Date addDateHours(Date date, int hours) { DateTime dateTime = new DateTime(date); return dateTime.plusHours(hours).toDate(); } /** * 对日期的【天】进行加/减 * * @param date 日期 * @param days 天数,负数为减 * @return 加/减几天后的日期 */ public static Date addDateDays(Date date, int days) { DateTime dateTime = new DateTime(date); return dateTime.plusDays(days).toDate(); } /** * 对日期的【周】进行加/减 * * @param date 日期 * @param weeks 周数,负数为减 * @return 加/减几周后的日期 */ public static Date addDateWeeks(Date date, int weeks) { DateTime dateTime = new DateTime(date); return dateTime.plusWeeks(weeks).toDate(); } /** * 对日期的【月】进行加/减 * * @param date 日期 * @param months 月数,负数为减 * @return 加/减几月后的日期 */ public static Date addDateMonths(Date date, int months) { DateTime dateTime = new DateTime(date); return dateTime.plusMonths(months).toDate(); } /** * 对日期的【年】进行加/减 * * @param date 日期 * @param years 年数,负数为减 * @return 加/减几年后的日期 */ public static Date addDateYears(Date date, int years) { DateTime dateTime = new DateTime(date); return dateTime.plusYears(years).toDate(); }
    获取IP地址
    ** * 获取IP地址 * * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址 * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址 */public static String getIpAddr(HttpServletRequest request) { String ip = null; try { ip = request.getHeader("x-forwarded-for"); if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } } catch (Exception e) { logger.error("IPUtils ERROR ", e); }
    分页插件
    //分页参数long curPage = 1;long limit = 10;if(params.get(Constant.PAGE) != null){ curPage = Long.parseLong((String)params.get(Constant.PAGE));}if(params.get(Constant.LIMIT) != null){ limit = Long.parseLong((String)params.get(Constant.LIMIT));}//分页对象Page<T> page = new Page<>(curPage, limit);//分页参数params.put(Constant.PAGE, page);//排序字段//防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险)String orderField = SQLFilter.sqlInject((String)params.get(Constant.ORDER_FIELD));String order = (String)params.get(Constant.ORDER);//前端字段排序if(StringUtils.isNotEmpty(orderField) && StringUtils.isNotEmpty(order)){ if(Constant.ASC.equalsIgnoreCase(order)) { return page.addOrder(OrderItem.asc(orderField)); }else { return page.addOrder(OrderItem.desc(orderField)); }}//没有排序字段,则不排序if(StringUtils.isBlank(defaultOrderField)){ return page;}//默认排序if(isAsc) { page.addOrder(OrderItem.asc(defaultOrderField));}else { page.addOrder(OrderItem.desc(defaultOrderField));}return page;
    5.业务代码/** * 所有申请列表 */@RequestMapping("/list")@RequiresPermissions("person:apply:list")public R list(@RequestParam Map<String, Object> params) { if(getRoleId() == 5){ //不是管理员只能查看自己工资记录 params.put("applyUserId", getUserId()); } PageUtils page = convertApplyService.queryPage(params); return R.ok().put("page", page);}/** * 申请信息 */@RequestMapping("/info/{id}")@RequiresPermissions("person:apply:info")@ResponseBodypublic R info(@PathVariable("id") Long id) { ConvertApplyEntity apply = convertApplyService.getById(id); return R.ok().put("apply", apply);}/** * 保存申请 */@SysLog("保存申请")@RequestMapping("/save")@RequiresPermissions("person:apply:save")public R save(@RequestBody ConvertApplyEntity apply) { ValidatorUtils.validateEntity(apply); apply.setApplyUserId(getUserId()); apply.setCreateTime(DateUtils.currentTimeFormat()); convertApplyService.save(apply); return R.ok();}/** * 修改申请 */@SysLog("修改申请")@RequestMapping("/update")@RequiresPermissions("person:apply:update")public R update(@RequestBody ConvertApplyEntity apply) { ValidatorUtils.validateEntity(apply); if (!apply.getStatus() .equals(ApplyStatusEnum.WAIT.getCode())) { return R.error("已审批不可修改"); } apply.setUpdateTime(DateUtils.currentTimeFormat()); convertApplyService.update(apply); return R.ok();}/** * 审核 */@SysLog("审核")@RequestMapping("/approval")@RequiresPermissions("person:apply:approval")public R approval(@RequestBody ConvertApplyEntity apply) { ValidatorUtils.validateEntity(apply); if(apply.getApprovalUserId()==getUserId()){ return R.error("自己不能审批自己的申请"); } if(ApprovalStatusEnum.ADOPT.getCode()== apply.getApprovalResult()){ apply.setStatus(ApplyStatusEnum.ADOPT.getCode()); }else{ apply.setStatus(ApplyStatusEnum.FAIL.getCode()); } apply.setApprovalUserId(getUserId()); apply.setUpdateTime(DateUtils.currentTimeFormat()); convertApplyService.update(apply); return R.ok();}/** * 删除申请 */@SysLog("删除申请")@RequestMapping("/delete")@RequiresPermissions("person:apply:delete")public R delete(@RequestBody Long[] ids) { convertApplyService.deleteBatch(ids); return R.ok();}
    /** * 招聘要求 * * @author */@RestController@RequestMapping("/person/need")public class RecruitNeedController extends AbstractController { @Autowired private RecruitNeedService recruitNeedService; /** * 所有招聘要求列表 */ @RequestMapping("/list") @RequiresPermissions("person:need:list") public R list(@RequestParam Map<String, Object> params){ PageUtils page = recruitNeedService.queryPage(params); return R.ok().put("page", page); } /** * 招聘要求信息 */ @RequestMapping("/info/{id}") @RequiresPermissions("person:need:info") @ResponseBody public R info(@PathVariable("id") Long id){ RecruitNeedEntity need = recruitNeedService.getById(id); return R.ok().put("need", need); } /** * 保存招聘要求 */ @SysLog("保存招聘要求") @RequestMapping("/save") @RequiresPermissions("person:need:save") public R save(@RequestBody RecruitNeedEntity need){ ValidatorUtils.validateEntity(need); need.setCreateTime(DateUtils.currentTimeFormat() ); recruitNeedService.save(need); return R.ok(); } /** * 修改招聘要求 */ @SysLog("修改招聘要求") @RequestMapping("/update") @RequiresPermissions("person:need:update") public R update(@RequestBody RecruitNeedEntity need){ ValidatorUtils.validateEntity(need); recruitNeedService.update(need); return R.ok(); } /** * 删除招聘要求 */ @SysLog("删除招聘要求") @RequestMapping("/delete") @RequiresPermissions("person:need:delete") public R delete(@RequestBody Long[] ids){ recruitNeedService.deleteBatch(ids); return R.ok(); }
    四、项目部署
    导入mysql脚本,数据库名称:person_system修改数据库配置:


    启动java工程(执行person-admin工程com.person.AdminApplication.class中main方法)


    访问:http://localhost:8888(账号admin/admin)
    五、项目实现管理员

    财务专员

    人事专员

    普通用户

    所有功能介绍
    0.登录
    登录地址:http://localhost:8888/账号密码:admin/admin

    1.绩效考核绩效考核目前只做了简单的考核设置,后期可扩展更多功能与工资和培训挂钩。后期会从以下几个方面扩展:

    季度考核不达标需要参加培训;考核不达标影响绩效;在公司做培训增加绩效;

    2.招聘管理招聘管理子模块:招聘需求和面试计划。招聘需求是为各个部门需要人才时到招聘需求申请,申请成功后,由人事部门和招聘部门协商面试时间添加面试计划,并跟踪面试结果。
    (1)招聘需求可由人事部门或有招聘需求部门填写招聘需求。
    (2)面试计划人事专员看到各个部门的招聘需求后,联系候选人并和用人部门协商面试时间,并将面试计划提交,等面试结束再将面试结果同步到系统。招聘结束后结束流程。
    3.档案管理档案管理子模块:员工档案和合同管理。
    (1)员工档案员工档案是“系统管理-账号管理”的延伸,即“系统管理-账号管理”是系统的登录账号信息,而员工档案是对账号信息的补充。必须由管理员先创建好账户,才能添加员工档案
    (2)合同档案公司商业合同管理
    4.工资管理工资管理目前有工资查询子模块。普通用户可查看自己工资记录,财务专员可增加员工工资记录。
    5.考勤管理考勤管理目前有出勤记录子模块。普通用户可每日打卡,查看出勤记录,后期可扩展与工资计算挂钩。
    6.培训管理培训管理子模块:个人计划,工作日报,转正申请和工作日报。
    (1)个人计划员工可写当日工作计划
    (2)工作日报员工可写当日工作日报
    (3)转正申请员工到了转正日期可申请转正由其领导进行审批。后期可与工资和绩效挂钩进行扩展,扩展内容如下:

    转正前工资按合同80%计算,转正后100%;转正后绩效不达标则绩效奖金按百分比算

    (4)培训计划可添加新员工培训计划,新技能培训计划,新业务培训计划,后期可扩展会议室管理功能
    7.系统管理系统管理子模块:员工管理,部门管理,角色管理,菜单管理和字典管理。
    (1)账号管理可为新员工增加系统登录账号,为离职员工删除账号。后期可扩展员工忘记密码后,重置密码功能,通常只有人事专员和管理员可用
    (2)部门管理可增加新部门或新成立子公司,通常只有管理员和高级管理领导可用
    (3)角色管理可新增角色,并为角色赋予相应权限,如招聘专员只能操作系统管理模块以外的其他模块功能,从财务专员只能进行工资记录添加等,通常只有管理员和高级管理领导可用
    (4)菜单管理管理系统左侧的菜单树,只有管理员可用
    (5)字典管理管理系统常用字典值,只有管理员可用
    六、总结1.报错整理
    tomcat端口号占用,一般是eclipse非正常关闭,或者电脑强制性关机等导致的,需要避免;如果产生,在终端查询被占用的端口号,并终止其进程即可学会利用eclipse的快捷键来生成无参、有参函数和set、get方法;同时学会配置个人偏好设置,便于eclipse预测要输入的内容。需要补充多表链接查询的知识,便于项目的后续维护和更新。要学习html5和css样式的知识,对网页页面的样式进行优化。在遇到错误无法解决的时候,一定要有耐心,即使可能一个小小的错误要花3-4小时来解决,也不要随随便便放弃,要一点点从根源查起,尽可能自己去解决问题。团队成员之间要互相协作、互相帮助,团队中的每个成员应该考虑团队的整体进度,积极去完成自己的部分;当然在完成自己的模块之后也应该给遇到困难的成员提供一定的帮助,加快整体的完成进度。页面报错404 — 一般都是路径错误,或者配置文件错误等等500 — 可能是多种错误导致的,可能是拼写错误,数据库sql语句错误等
    2.项目总结开发体会:在此次项目开发过程中我们学到了很多,一个项目的完成并不是那么的容易。要制度遇到问题时该如何去分析问题、解决问题。团队的分工与合作是提高效率的关键。
    其次是对设计的先后顺序有了一定的认识,对于做软件设计来说,首要的就是要搞清用户需求,也就是别人要干什么,然后再决定怎么干!一般情况下这时候要知道,谁来用这个系统,什么时候用这个系统,什么地方用这个系统,为什么用这个系统,用这个系统干什么,最后再搞清楚怎么做这个系统.在做需求分析的时候首先得跟客户沟通得出大致的需求,形成一个资料,然后再与客户探讨看看自己理解的业务有没有问题.我认为在与客户沟通之前最好对这个系统的概况有个大体的了解,这样也有利于交流,但不管怎么做与客户交流都是最重要的,如果一开始与客户的交流出了问题,以后作的过程中业务就会出问题,轻则反反复复的改,重则系统失败.需求设计以后就是概要设计,也就是考虑具体怎么做的时候.这时候做的方法有可能不同,但有一点应该是一样的,就是系统细化成各个小的功能块,同时决定数据库,之后就可以对每个功能块做详细设计了.概要设计时也要紧紧围绕业务来做,也要多交流,多与客户交流,同时项目组里也要多讨论!在这个时候要考虑共通化的问题,比如说画面的样式,数据库字段的命名什么的.还有就是操作是否方便,这个必须得好好考虑.一个系统用人工方式一般也能做,用信息管理系统就是为了方便,结果你设计的东西还没人家手工方式方便呢,那还有谁回用啊!另外,安全性什么的也要考虑一下尤其是个人的信息!
    最后想说的就是交流的能力,这个很重要.一方面是你得想说,同时能把想说的话说清楚.会说的同时也要会听给别人一些说的机会.再有就是态度,要真诚的与人交流,同时要微笑着与人交流.微笑能解开别人的疑虑,即使有不同意见,别人一般也不会认为你是故意跟他作对,这样的话交流才能进行下去!
    0  留言 2021-09-19 13:42:18
  • 基于Springboot和Mysql实现的大学生招聘网站系统

    1.项目简介1.1 系统研究背景伴随着中国经济的飞速发展,城市化进程的加快,求职者队伍的不断壮大,传统人才招聘的弊端初露端倪。首先,传统人才应聘的形式是求职者和企业的负责人面对面地交流。这就需要企业和求职者提前规划自己的时间,准备大量的纸质材料,并选好举办招聘会的地点,这一系列流程都需要双方把大量的精力投入到准备活动中去,使得应聘还未开始,成本就已大幅增加。其次,企业在筛选数以百计,甚至数以万计简历的时候,往往会由于阅读疲劳,漏掉一些真正有价值的简历,使得企业丧失掉一批有用的人才。对于求职者而言,也会错失掉良好的机会,令人惋惜。
    随着国内互联网飞速的发展,人们已经越来越习惯于使用互联网传递信息,接收信息,利用互联网技术使得自己的生活更加便利,快捷。在这样一种大趋势下,网上人才招聘系统出现在了人们的眼前。而且由于网络招聘较传统招聘具有多项优势,越来越多的求职者选择网络求职成为自己的应聘方式。
    1.2 系统研究意义本系统开发的意义一方面在于突破传统人才招聘的模式,给招聘者和求职者提供一个便利、高效、准确的网络招聘平台,使得双方可以在把成本降到最低的前提下,在更快的时间获得更加准确的信息,从而满足企业的用人需求,实现求职者的自我价值。另一方面在于完善网络招聘服务工作,建立服务体系,通过对用户需求的研究,开发出更符合实际应用的软件。
    1.3 开发环境
    操作系统:Windows10
    数据库版本:Oracle10g XE
    JDK版本:JDK1.8
    服务器版本:apache-tomcat-8.0.24-windows-x64

    1.4 技术栈
    后端 :Java、Springboot、redis、MyBatis
    前端:HTML+CSS实现页面布局,部分功能使用Jquery和Ajax减轻服务器端的压力

    2.系统设计2.1 系统设计模块
    2.2 功能模块
    个人用户:注册,登录,修改密码
    个人信息管理:查看,修改个人信息
    求职信息管理:修改自己的求职信息;发布自己的求职信息
    简历管理:查看,修改简历信息

    2.3 数据库设计2.3.1 表结构公司表

    公司管理员表

    公司收到简历表

    用户表

    获奖表

    职位表

    项目经验表

    简历表

    简历投递记录表

    专业技能表

    工作经验表

    2.3.2 E-R图
    3.系统实现3.1 业务代码/** * @param username 手机号/邮箱 * @param password 密码 * @param userType 0手机号;1邮箱 * @return 结果集 */@Overridepublic ServerResponse getByUsernameAndPwd(String username, String password, Integer userType) { CustomerExample example = new CustomerExample(); CustomerExample.Criteria criteria = example.createCriteria(); criteria.andStatusEqualTo(0); if (userType == 0) criteria.andCustTelnoEqualTo(Long.valueOf(username)); else criteria.andCustEmailEqualTo(username); criteria.andCustPasswordEqualTo(password); List<Customer> customerList = customerMapper.selectByExample(example); if (customerList != null) { if (customerList.size() == 1) return ServerResponse.getSuccess(customerList.get(0)); else if (customerList.size() > 1) return ServerResponse.getFailed("用户异常,请联系管理员"); } return ServerResponse.getFailed("用户名/密码错误,请重试");}@Overridepublic ServerResponse add(Customer customer) { customer.setCustRegistTime(new Date()); customer.setStatus(0); int rows = customerMapper.insert(customer); if (rows > 0) return ServerResponse.addSuccess(); return ServerResponse.addFailed();}@Overridepublic ServerResponse getByTelno(Long custTelno) { CustomerExample example = new CustomerExample(); example.createCriteria().andCustTelnoEqualTo(custTelno).andStatusEqualTo(0); List<Customer> customerList = customerMapper.selectByExample(example); if (customerList != null && customerList.size() > 0) {//找到用户了 return ServerResponse.getSuccess(customerList.get(0)); // 1,"查询数据成功",customer } else // 用户不存在 return ServerResponse.getFailed("用户不存在"); // 0,"查询数据失败","用户不存在"}
    3.2 前端代码<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %><link rel="stylesheet" href="${pageContext.request.contextPath}/css/navigate.css"><div id="index_head"> <div id="logoInfo"> <div id="address"> <img id="addressimg" src="${pageContext.request.contextPath}/images/jkf_imgs/address.svg" alt="苏州"> <span>当前城市[<span id="addresssp"></span>]</span> </div> <ul id="home"> <li><a href="${pageContext.request.contextPath}/">首页</a></li> <li><a href="${pageContext.request.contextPath}/job/jobInfo">职位</a></li> </ul> <c:if test="${sessionScope.loginCustomer==null}"> <div class="loginPart"> <ul> <li> <a href="${pageContext.request.contextPath}/login">投递记录</a> </li> <li> <a href="${pageContext.request.contextPath}/login">简历</a> </li> <li> <a href="${pageContext.request.contextPath}/login" class="clickBtn">登录</a> </li> <li> <a href="${pageContext.request.contextPath}/register" class="clickBtn">注册</a> </li> </ul> </div> </c:if> <c:if test="${sessionScope.loginCustomer!=null}"> <div class="loginPart"> <ul> <li> <a href="${pageContext.request.contextPath}/customer/center/2">投递记录</a> </li> <li> <a href="${pageContext.request.contextPath}/customer/center/1">简历</a> </li> <li> <a href="${pageContext.request.contextPath}/customer/center/0"> <span class="label-text">${sessionScope.loginCustomer.custName}</span> <%--<img src="" alt="用户头像">--%> </a> </li> <li> <a href="${pageContext.request.contextPath}/customer/logout">退出登录</a> </li> </ul> </div> </c:if> </div></div><script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=f33ff318925b81fd4f3773c5a1efa107&plugin=AMap.CitySearch"></script><script type="text/javascript"> var map = new AMap.Map("container", { resizeEnable: true, center: [116.397428, 39.90923], zoom: 13 }); //获取用户所在城市信息 function showCityInfo() { //实例化城市查询类 var citysearch = new AMap.CitySearch(); //自动获取用户IP,返回当前城市 citysearch.getLocalCity(function(status, result) { if (status === 'complete' && result.info === 'OK') { if (result && result.city && result.bounds) { var cityinfo = result.city; var citybounds = result.bounds; document.getElementById('addresssp').innerHTML = cityinfo; //地图显示当前城市 map.setBounds(citybounds); } } else { document.getElementById('addresssp').innerHTML = result.info; } }); } showCityInfo();</script><script> let ROOTSources = "${pageContext.request.contextPath}";</script>
    4.项目展示登录

    主页

    职位详情

    公司简介

    投递记录

    编辑简历

    简历列表

    申请职位



    5.总结第一次接触实际项目遇到使用新的开发工具感觉很陌生,移动web开发也是第一次接触,对开发工具的陌生情况下也遇到很多问题,比如说HBuilderX移动web开发工具在手机上调试遇到的问题,必须搭建iis服务器以及HBuilderX在局域网必须要同一级IP,否则链接不了,手机调试不了。公司实际项目都是以团队开发,团队协调很重要,比如说每个人使用不同的用户登录进行开发不同模块的功能,从而删除别的开发人员的相关的数据,导致每个使用到这个用户的数据混乱。
    最重要是数据库设计,数据库不是我们设计,对于数据库设计的人设计出来的任务逻辑出现各种各样问题,不符合业务逻辑需求,从而导致项目进度拖慢。UI设计也是我们的弱项,没有用专门去研究过UI设计风格以及设计视觉原理,从而导致项目开发进度拖慢。IM即时聊天要求也比较高,也是对于初次开发要对网络编程十分了解,需要耗费很多时间,从而导致项目开发进度拖慢。在开发过程遇到这些问题,我就可以知道自己的弱点以及开发中必须要用到的一些常用的技术。比如说MUI框架、Amaze UI框架、Frozen UI框架、SUI框架、ZUI框架、H-ui框架、UIkit框架、Bootstrap框架、Plane UI框架、WeUI框架等移动web的前端框架,对框架使用是否熟悉;接着图片的上传和下载,对流操作熟悉。
    0  留言 2021-09-19 09:55:26
  • 基于MVC的社团信息管理系统

    第一章 目的与意义1.1 系统开发的背景社团作为各高校的重要组成部分之一,是高校校园文化的重要体现,涉及到学院社团和成员等重要信息。从会员加入社团到退出社团,包含了很多信息,如活动信息,加分信息等等。从社团的建立到撤销,也是含有非常多的信息,如活动的举办,会员的管理等等重要信息。尤其是随着对大学生课外拓展,第二课堂的测评工作的改革,对社团的日常管理也变得现代化和数字化。如果在使用传统的人工管理方式,既繁琐、又不能实现数据共享,同时数据的安全性也没有保障。所以,开发一个功能较好、操作简单,同时又能规范准确的社团信息管理系统是非常有必要的。
    1.2 系统设计的目的与意义1.2.1 个人信息模块在一个系统中,用户只要一注册,系统为了方便用户的下次登录,就会存有用户注册时填下的个人信息。但如果用户忘记了自己填写的个人信息,要如何查看呢?如果用户的个人信息发生的改变,又该如何及时的让系统知道呢?此时,个人信息模块的重要性就体现出来了。在个人信息这个模块里,用户可以随时的查看自己的个人资料,并可以个性化的进行更改。这样既可以提高用户的体验效果,又可以方便系统及时对用户的信息进行更新。很多完整且大型的系统都是会有用户信息的模块的,比如QQ、微信等等。想象一下,没有个人信息模块,就像是你无法查看和更改你在QQ里的个人信息,包括不可以修改你的用户名,生日或是个性签名。那样的感觉是不是很糟糕。所以,个人信息模块是一个系统里不可缺少的一部分。
    1.2.2 社团信息模块这个系统是社团信息管理系统,社团信息模块是系统里最基本的,也是最重要的模块之一,社团信息里有了社团的基本信息,包括社团编号、社团名称、社团资金、社团地址以及指导老师。普通用户可以通过查看社团的这些基本信息来了解社团,选择是否加入该社团。社团干部可以查看修改社团的这些基本信息,达到及时更新信息的目的,有利于建设更好的社团,协助社团管理。管理员不仅可以通过社团信息这个模块,对社团信息进行增删改查,还可以在这里对新申请的社团进行审核,或是对经营不善的社团进行撤销。
    1.2.3 活动信息模块每一个社团的创建都是因为有一群志趣相投的人聚在了一起,做一些他们都感兴趣的事情。社团活动就是他们对这个共同的兴趣做事情的体现。一个没有社团活动的社团,常常被称之为“没有灵魂的社团”。活动信息模块是附属于社团信息模块的一个部分,每一个社团都有它举办的活动,如舞蹈协会的舞蹈演出,魔术协会的魔术表演,电子协会的义修等等。在每学年的综测评比中,参加社团的活动的同学可以得到一定的技能加分,所以,一个管理这些信息的模块由此诞生,活动信息模块也是活动加分模块。
    1.2.4 成员信息模块要管理好一个社团,自然需要一定的层次分布,否则群龙无首,意见众多的时候,会乱成一团,所以在社团里往往会有社团会长、副会长、理事已经普通会员的分布。同样对于社团干部拥有社团成员的信息综合表是不可缺少的,除了更准确的把握成员信息,保障社团基本安全性之外,也是为了避免在后续管理中会出现各种各样的麻烦。如,社团干部需要对参加了活动的会员进行加分录入,如果不能及时拿到会员的基本信息会给工作带来极大的不便,此外管理员对系统的安全保障也会有所困难。
    1.2.5 用户信息模块用户信息模块是每个系统都必不可少的模块,它从用户注册时获取用户信息,在用户登录时为系统提供查询登录的作用,因为拥有用户信息,系统才能保障每个注册过的用户可以顺利登录,也保障登录的是注册过的用户。管理员拥有了用户信息才能更好的给予不同的用户一定的权限,管理好系统的进入人员,保障系统的基本安全。用户信息表还给各个用户的个人资料模块提供信息。
    1.2.6 统计信息模块经验证明,统计可以更集中、更系统、更清楚的反映客观实际,统计分析是为管理者提供更直观的信息,有助于更准确的决策和判断。统计信息模块,可以为管理员提供更直观的社团数据,成员数据以及男女比例,有助于更明了系统里的数据变化,及时了解情况。
    第二章 理论基础及技术路线2.1 Java Web设计模式随着计算机软硬件技术的高速发展以及计算机网络的普及,软件应用已经从以往的单机软件扩展到了基于网络的软件,并随之产生了基于Internet的Web应用程序,Java作为业内重要的软件开发语言,也提供了Web应用的开发机制。Java Web 是用Java技术来解决相关Web互联网领域的技术总和。Web包括服务器和客户端两部分,Java在客户端的应用原本就有Java Applet,不过目前用得很少,而Java在服务器端的应用则非常丰富,比如Servlet、JSP和第三方框架等。Java技术对Web领域的发展注入了强大的动力。
    在该社团信息系统的构建过程中,就运用了大量的Servlet和JSP。
    2.2 MySQL设计模式MySQL是一个关系型数据库管理系统,由瑞典的MySQL AB公司开发,目前属于Oracle旗下的公司。MySQL是最流行的关系型数据库管理系统,在WEB应用方面,MySQL是最好的RDBMS应用软件之一。MySQL是一种关联数据库将数据保存在不同的表中,而不是将所有的数据放在一个大仓库内,这样就加快了速度并提高了灵活性。MySQL所使用的SQL语言是用于访问数据库的最常用标准化语言。MySQL软件采用了双授权政策,它分别为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择MySQL作为网站数据库。由于其社区版的性能卓越,搭配JSP、PHP和Apache可以组成良好的开发环境。
    在社团信息管理系统中,运用了MySQL创建了四张表,分别是成员表:member、社团表:club、活动表:activity、用户表:user;通过数据查询语句创建了多个方法,尤其是在构建社团统计信息的方法的时候,运用了大量的MySQL语句。
    2.3 XML设计模式XML是可扩展标记语言,也是元标记语言,定义了用于定义其他与特定领域有关的、语义的、结构化的标记语言的句法语言,用户可以定义自己需要的标记。XML标记描述的是文档的结构和意义,它不描述页面元素如何显示。XML为基于Web的应用程序带来了强大的功能和灵活性,它为开发人员和用户提供了许多优点。总的来说,XML的应用可分为四类分别是:应用于客户需要与不同的数据源进行交互、应用于将大量运算负荷分布在客户端、应用于将同一数据以不同的面貌展现给不同的用户和应用于内容与配置管理。
    在该社团信息管理系统中,就存在由XML文件,如,database.conf.xml和web.xml,是系统构建过程中非常重要的组成部分,每每构建一个servlet都需要去web.xml里面添加一些信息,xml元素必须遵循一些命名规则,比如,名称不能以数字或标点符号开始,不能以字符“xml”开始,不能包含空格等等。
    2.4 Servlet 设计模式2.4.1 ServletServlet是在服务器上运行的小程序,这个词是在Java applet的环境中创造的,Java applet 是一种当作单独文件与网页一起发送的小程序,它通常在客户端运行,然后得到为用户进行运算或者根据用户互作用定位图形等服务。最早支持Servlet技术的是JavaSoft的Java Web Servlet。此后,一些其他基于Java的Web Servlet 开始支持标准的Servlet API。Servlet的主要功能是交互式的浏览和修改数据,生成动态Web内容。
    Servlet的基本流程是:客户端通过HTTP提出请求、Web服务器接收该请求并将其发给Servlet、Servlet将接收该HTTP请求并执行某种处理、Servlet将向Web服务器返回应答、Web服务器将从Servlet收到的应答发送给客户端。
    Servlet的特点是:平台无关性、持久性、可扩展性、安全性、可以在多种多样的客户机上使用。
    在社团信息管理系统中,我一共构建了28个Servlet,每一个都带着不同的功能和作业,每每构建一个servlet就需要去web.xml中添加信息,尤其要注意最后的路径,极容易写错。在jsp页面中触发,在servlet页面中调用对应的函数,然后再返回jsp页面,必要时可以借助form的帮忙触发servlet。
    2.4.2 SessionSession就是会话,是客户为实现应用目的与系统的多次请求交互。会话跟踪允许服务器跟踪同一个客户端作出的连续请求,使得服务器应用程序可以保持客户应用的相关信息。会话跟踪常用的方法包括使用Cookie、URL重写、隐藏表单域等技术。
    其中会话跟踪API是本系统中使用最多的session,它的主要操作有:查看与当前请求关联的会话对象、查看与会话相关的信息、在会话对象中保存数据、废弃会话数据。
    该社团信息管理系统在登录页面多次使用session获取用户信息,保存数据,将其在需用的地方输出,进行数据的获取输出,不断重复使用,只要保存一次,在不同的位置都可以获取得到。
    2.4.3 FilterFilter是小型的Web组件,用于拦截请求和响应,以便查看、提取或以某种方式操作正在给客户机和服务器之间交换的数据。过滤器是封装了一些功能的Web组件,这些功能虽然重要,但是对于处理客户机请求或发送响应来说不是决定性的。Filter结合了去多元素,从而使得过滤器成为独特、强大和模块化的Web组件。它有如下特点:声明的、动态的、灵活的、模块化的、可移植的、可重用的和可透明的。它的实现有三个步骤:编写一个过滤器实现类、把过滤器添加到Web应用程序中、把过滤器与应用程序一起打包并部署它。
    在社团信息管理系统中,Filter文件有AuthorityFilter.java,主要是用于过滤掉非管理员,设置在admin文件夹下的jsp只有管理员才能访问,非管理员则没有权限访问。
    2.5 JSP设计模式JSP技术能够让程序开发人员建立起功能强大的动态网页内容,实现HTML、JavaScript等静态技术与Java代码等动态技术混合编码。在传统的HTML页面文件中加入Java程序片和JSP标签就构成了一个JSP页面文件。简单的说,一个JSP页面除了普通的HTML标记外,再使用标记符号“<%”和“%>”加入Java程序片。一个JSP页面可以由以下5种元素组合而成:普通的HTML标签、JSP标签、变量和方法的声明、Java程序片和Java表达式。
    在社团信息管理系统中,运用了大量的jsp页面,几乎所有的界面使用的都是jsp,jsp可以使用java的程序语言给功能的实现带来了很大的便利。其中有一种处理汉字信息的代码十分的有用:
    String str = request.getParameter(“girl”);byte b[] = str.getBytes(“ISO-8859_1”);str = new String(b);
    2.6 JavaScript设计模式JavaScript 是一种基于对象和事件驱动并具有相对安全性的客户端脚本语言。同时也是一种广泛用于客户端Web开发的脚本语言,常用来给HTML网页添加动态功能,比如响应用户的各种操作。它的特点有:简单性、安全性、动态性和跨平台性。JavaScript可以出现在HTNL的任意地方。使用标记<script>…</script>,可以在HTML文档的任意地方插入JavaScript,甚至在<HTML>之前插入也没有问题。不过如果要在声明框架的网页中插入,就一定要在<frameset>之前,否则不会运行。页面插入JavaScript还有一种方法,就是把JavaScript代码写到另一个文件中去,然后格式为“<script src = “javascript.js”</script>”的标记把它嵌入到文档中即可。
    在社团信息管理系统中,遇到一些需要填表的地方,有些会有js设置写入的格式,或者是不可以留空之类的,如果违反了,浏览器页面就会弹出对应的提示框。
    2.7 MAV 设计模式MVC是一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。它的优点是能为应用程序处理很多不同的视图。在视图中其实没有真正的处理发生,不管这些数据是联机存储的还是一个雇员列表,作为视图来讲,它只是作为一种输出数据并允许用户操纵的方式。
    第三章 模块总体设计3.1 需求分析岭南师范学院是国家教育局批准的全日制高等二本院校。学院涵盖有100多个不同的社团,是校园文化的重要体现。校社联机构在日常管理工作中,总需要处理有关社团信息的处理,如,社团信息的变更,活动内容的更新,活动加分的申请等等。岭南师范学院的社团在每年的11月份都要进行社团成员的更新,包括旧成员的退出,新成员的加入,社团的申请,以及社团经营不善被撤销等等问题。近年,随着国家对高校社团改革的要求,学院里社团信息管理工作中的数据量也迅速增加,如果能够拥有一个功能较好的社团信息管理系统来实现对社团信息的管理,将极大的减轻学院社团信息管理的负担,提高社团管理的效率。
    3.1.1 用户具体需求分析
    普通用户:能够随时查询和修改个人信息、申请新社团、查看社团信息、加入社团以及查看自己加入了社团的信息
    社团干部(会长):能够查看和修改个人信息、可以增删改查所有社团的基本信息、审核普通用户申请加入社团、对社团所有会员信息进行增删改查、对社团所有活动进行增删改查
    管理员:能够查看和修改个人信息,能够对所有社团的社团信息、成员信息、活动信息、以及系统用户信息进行增删改查,可以审核普通用户申请的新社团和申请加入社团的要求,还可以查看系统所有社团的统计信息情况表

    3.1.2 功能需求分析要对岭南师范学院的社团信息进行全面的管理,系统需要拥有良好的功能及界面。系统的主要数据操作还是增删改查,同时提供一个较为方便的平台,高效的实现对社团信息的管理,根据实际工作需求,系统需要具备的功能有:

    界面设计合理,界面友好
    权限要求:主要有普通用户、社团干部和管理员三个角色。管理员是系统的管理者,拥有最高权限,可以对所有数据进行设置,更改等操作。社团干部的权限仅次于管理员,拥有部分权限,仅可以修改查看自己权限范围内的信息。用户可以修改自己的信息,以及对管理员发出申请的请求等功能

    3.2 功能结构设计3.2.1 普通用户界面普通用户拥有的功能模块:

    3.2.2 社团干部(普通管理员)界面社团干部拥有的功能模块:

    3.2.3 高级管理员界面管理员拥有的功能模块:

    3.3 数据库设计3.3.1 数据字典数据字典表



    数据项编号
    数据项名
    数据项含义
    与其它数据项的关系
    存储结构
    是否允许为空




    1
    cId
    社团编号

    varchar(10)



    2
    cName
    社团名称

    varchar(50)



    3
    cPlace
    社团地点

    varchar(50)



    4
    cFree
    社团资金

    int



    5
    teacher
    指导老师

    varchar(20)



    6
    Signs
    状态

    varchar(20)



    7
    mId
    成员编号
    外键
    varchar(10)



    8
    cId
    社团编号
    外键
    varchar(10)



    9
    cAct
    加分

    int



    10
    mId
    成员编号

    varchar(10)



    11
    mName
    成员名称

    varchar (20)



    12
    mGender
    性别

    varchar (2)



    13
    cName
    社团名称

    varchar (50)



    14
    prof
    职位

    varchar(20)



    15
    Sign
    状态

    varchar (20)



    16
    mId
    成员编号

    char (10)



    17
    username
    用户名

    char(20)



    18
    password
    密码

    char(20)



    19
    ssuper
    权限

    int




    3.3.2 ER图
    3.3.3 数据库表设计该数据库有四张表,分别是:成员表:member、社团表:club、活动表:activity、 用户表:user;
    成员表



    名称
    数据类型
    允许空
    主键
    说明




    cId
    varchar


    社团编号


    cName
    varchar


    社团名称


    cPlace
    varchar


    社团地点


    cFree
    int


    社团资金


    teacher
    varchar


    指导老师


    Signs
    varchar


    状态



    活动表



    名称
    数据类型
    允许空
    主键
    说明




    mId
    varchar


    成员编号


    cId
    varchar


    社团编号


    cAct
    int


    加分值



    成员表



    名称
    数据类型
    允许空
    主键
    说明




    mId
    varchar


    成员编号


    mName
    varchar


    成员名称


    mGender
    varchar


    性别


    cName
    varchar


    社团名称


    prof
    varchar


    职位


    Sign
    varchar


    状态



    用户表



    名称
    数据类型
    允许空
    主键
    说明




    mId
    char


    成员编号


    username
    char


    用户名


    password
    char


    密码


    ssuper
    int


    权限



    3.3.4 业务流程图用户视角的简单业务流程图:

    3.3.5 数据流程图顶层数据流图

    零层数据流图(普通用户视角)

    一层数据流图(管理员视角)

    第四章 系统实现4.1 整体情况工程的全部文件夹截图



    登录界面

    注册界面

    管理员用户界面

    普通用户界面截图

    4.2 用户模块4.2.1 个人资料模块个人资料模块的部分代码和截图
    Servlet部分代码
    用从登录页面得到的用户登录账号,调用user()方法得到该登录用户的用户信息,返回到jsp页面
    //调用DAO查找HttpSession s = req.getSession();ServletRequest session = **null**;String mid = (String)session.getAttribute("mid");UserDAO ud = **new** UserDAO();Vector<User> v1 = ud.user(mid);s.setAttribute("personal",v1); //返回到jsp页面并显示查找到的所有信息resp.sendRedirect(req.getContextPath()+"/assets/personal.jsp");
    Jsp部分代码
    <form name="form" action="personal"> <table class="table"> <thead> <tr> <th>用户编号</th> <th>用户名</th> <th>密码</th> <th>权限 </th> <th></th> </tr> <% Vector<User> v = (Vector<User>)session.getAttribute("personal"); Iterator<User> it = v.iterator(); User u = null; while(it.hasNext()){ u = it.next(); if(!u.getmId().equals("01")){%><!-- 切断循环 --> <tr> <td><%=u.getmId() %></td> <td><%=u.getusername() %></td> <td><%=u.getpassword() %></td> <td><%=u.getssuper() %></td> <td><a href="updatepersonal.jsp?mid=<%=u.getmId() %>">修改</a></td> </tr> <% }}%>
    页面截图


    4.2.2 申请社团模块申请社团模块的部分代码和截图
    Servlet部分代码
    获取页面得到的申请信息,通过管理员审核后插入到社团表中:
    String cid = req.getParameter("cid");String cname = req.getParameter("cname");byte cname2[] = cname.getBytes("ISO-8859-1");cname = new String(cname2,"GBK");String cplace = req.getParameter("cplace");byte cplace2[] = cplace.getBytes("ISO-8859-1");cplace = new String(cplace2,"GBK");int cfree = Integer.parseInt(req.getParameter("cfree"));String teacher = req.getParameter("teacher");byte teacher2[] = teacher.getBytes("ISO-8859-1");teacher = new String(teacher2,"GBK");Club c = new Club();ClubDAO cd = new ClubDAO();c.setcId(cid);c.setcName(cname);c.setcPlace(cplace);c.setcFree(cfree);c.setTeacher(teacher);int flag = cd.insertInfoToClub1(c); if(flag == 1) resp.sendRedirect(req.getContextPath()+"/cheak.jsp");else resp.sendRedirect(req.getContextPath()+"/error-404.html");
    Jsp部分代码
    <form name="form" action="applyclub"> <div class="signin-form"> <div class="form-group"> <label for="signin_form">社团编号 </label> <input type="text"class="form-control" id="cid" name="cid" placeholder="社团编号"> </div> <div class="form-group"> <label for="signin_form">社团名称</label> <input type="text" class="form-control" id="cname" name="cname" placeholder="社团名称"> </div> <div class="form-group"> <label for="signin_form">社团所在地</label> <input type="text" class="form-control" id="cplace" name="cplace" placeholder="社团所在地"> </div> <div class="form-group"> <label for="signin_form">社团资金</label> <input type="text" class="form-control" id="cfree" name="cfree" placeholder="社团资金"> </div> <div class="form-group"> <label for="signin_form">指导老师</label> <input type="text" class="form-control" id="teacher" name="teacher" placeholder="指导老师"> </div> </div>
    结果截图


    4.2.3 社团报名模块社团报名模块的部分代码和截图
    Servlet部分代码
    查看所有社团信息
    ClubDAO jd = new ClubDAO();Vector<Club> v = jd.findAllClub();HttpSession s = req.getSession();s.setAttribute("allClub",v);//返回到joinclub.jsp页面并显示查找到的所有用户信息resp.sendRedirect(req.getContextPath()+"/assets/joinclub.jsp");
    Jsp部分代码
    <form name="form" action="joinclub"> <table class="table"> <thead> <tr> <th><input id="btn1" type="button" value="全选" onclick="allcheck();"/></th> <th>社团编号</th> <th>社团名称</th> <th>社团所在地</th> <th>社团资金</th> <th>指导老师</th> <th></th> </tr> <% Vector<Club> v = (Vector<Club>)session.getAttribute("allClub"); Iterator<Club> it = v.iterator(); Club c = null; while(it.hasNext()){ c = it.next(); if(!c.getcId().equals("01")){ %><!-- 切断循环 --> <tr> <td><input type="checkbox" name="check" value=<%=c.getcId() %>></td> <td><%=c.getcId() %></td> <td><%=c.getcName() %></td> <td><%=c.getcPlace() %></td> <td><%=c.getcFree() %></td> <td><%=c.getTeacher() %></td> <td><a href="joinclub1.jsp?cid=<%=c.getcId()%>">加入</a> </td> </tr> <% } } %>
    结果截图


    4.2.4 社团记录模块社团记录模块的部分代码和截图
    Servlet部分代码
    根据从登录页面获取的用户信息,筛选出该用户的成员信息,调用方法得到数据后,返回jsp页面
    //调用DAO查找HttpSession s = req.getSession();ServletRequest session = null;String mid = (String)session.getAttribute("mid"); MemberDAO md = new MemberDAO();Vector<Member> v1 = md.member(mid);s.setAttribute("myclub",v1);//返回到jsp页面并显示查找到的所有用户信息resp.sendRedirect(req.getContextPath()+"/assets/myclub.jsp");
    Jsp部分代码
    <table class="table"> <thead> <tr> <th>学号</th> <th>姓名</th> <th>性别</th> <th>社团</th> <th>职位</th> <th>状态</th> <th> </th> </tr> <% Vector<Member> v1 = (Vector<Member>)session.getAttribute("myclub"); Iterator<Member> it = v1.iterator(); Member m = null; while(it.hasNext()){ m = it.next(); if(!m.getmId().equals("01")){%><!-- 切断循环 --> <tr> <td><%=m.getmId() %></td> <td><%=m.getmName() %></td> <td><%=m.getmGender() %></td> <td><%=m.getcName() %></td> <td><%=m.getProf() %></td> <td><%=m.getSign() %></td> <td> <a href="outclub?f=del&mid=<%=m.getmId() %>" onclick = "return confirm('您确定要退出该社团吗?');">退出</a> </td> </tr> <% }}%></table>
    结果截图

    4.3 管理员模块4.3.1 社团信息模块社团信息模块的部分代码和截图
    Servlet部分代码
    //调用DAO查找所有社团信息ClubDAO cd = new ClubDAO();Vector<Club> v = cd.findAllClub();HttpSession s = req.getSession();s.setAttribute("allClub",v);//返回到club.jsp页面并显示查找到的所有用户信息resp.sendRedirect(req.getContextPath()+"/admin/allClub.jsp");
    Jsp部分代码
    <% Vector<Club> v = (Vector<Club>)session.getAttribute("allClub"); Iterator<Club> it = v.iterator(); Club c = null; while(it.hasNext()){ c = it.next(); if(!c.getcId().equals("01")){%><!-- 切断循环 --> <tr> <td><input type="checkbox" name="check" value=<%=c.getcId() %>></td> <td><%=c.getcId() %></td> <td><%=c.getcName() %></td> <td><%=c.getcPlace() %></td> <td><%=c.getcFree() %></td> <td><%=c.getTeacher() %></td> <td><%=c.getSigns() %></td> <td><a href="updateClub.jsp?cid=<%=c.getcId() %>">修改</a> <a href="updateClub?f=del&cid=<%=c.getcId() %>" onclick = "return confirm('您确定要删除该条记录吗?');">删除</a></td> </tr> <% }}%>
    结果截图

    4.3.3 活动加分模块
    活动加分模块的部分代码和截图
    Servlet部分代码
    //所有活动信息ActivityDAO ad = new ActivityDAO();Vector<Activity> v = ad.findAllActivity();HttpSession s = req.getSession();s.setAttribute("allActivity",v);resp.sendRedirect(req.getContextPath()+"/admin/allActivity.jsp");
    Jsp部分代码
    <% Vector<Activity> v = (Vector<Activity>)session.getAttribute("allActivity"); Iterator<Activity> it = v.iterator(); Activity a = null; while(it.hasNext()){ a = it.next(); if(!a.getmId().equals("01")){%><!-- 切断循环 --> <tr> <td><input type="checkbox" name="check" value=<%=a.getmId() %>></td> <td><%=a.getmId() %></td> <td><%=a.getcId() %></td> <td><%=a.getcAct() %></td> <td><a href="updateActivity.jsp?mid=<%=a.getmId() %>">修改</a> <a href="updateActivity?f=del&mid=<%=a.getmId() %>" onclick = "return confirm('您确定要删除该条记录吗?');">删除</a></td> </tr> <% }}%>
    结果截图

    4.3.4 成员信息模块成员信息模块的部分代码和截图
    Servlet部分代码
    MemberDAO md = new MemberDAO();Vector<Member> v = md.findAllMember();HttpSession s = req.getSession();s.setAttribute("allMember",v);//返回到member.jsp页面并显示查找到的所有用户信息resp.sendRedirect(req.getContextPath()+"/admin/allMember.jsp");
    Jsp部分代码
    //allmember.jsp的js代码function allcheck(){ var oCheck = document.getElementsByName('check'); for(var i=0;i<oCheck.length;i++){ oCheck[i].checked=true; }}function delAllMember(){ var allmid = new Array(); var flag = false; var oCheck = document.getElementsByName('check'); for(var i=0;i<oCheck.length;i++){ if(oCheck[i].checked){ allmid.push(oCheck[i].value); flag = true; } } if(flag){ if(confirm("您确定要删除这些记录吗?")){ location.href="updateMember?f=delall&allmid="+allmid; } }else{ alert("您至少需要选择一条记录才能进行批量删除!"); }
    结果截图

    4.3.5 用户信息模块用户信息模块的部分代码和截图
    Servlet部分代码
    //用户模块的“添加”的代码String mid = req.getParameter("mid"); String username = req.getParameter("username"); byte username1[] = username.getBytes("ISO-8859-1"); username = new String(username1,"GBK"); String password = req.getParameter("password1"); int ssuper = Integer.parseInt(req.getParameter("ssuper")); User u = new User(); UserDAO ud = new UserDAO(); u.setmId(mid); u.setusername(username); u.setpassword(password); u.setssuper(ssuper); int flag = ud.insertInfoToUser(u); if(flag == 1) resp.sendRedirect(req.getContextPath()+"/admin/findalluser"); else resp.sendRedirect(req.getContextPath()+"/error-404.html");
    Jsp部分代码
    <% Vector<User> v = (Vector<User>)session.getAttribute("allUser"); Iterator<User> it = v.iterator(); User u = null; while(it.hasNext()){ u = it.next(); if(!u.getmId().equals("01")){%><!-- 切断循环 --> <tr> <td><input type="checkbox" name="check" value=<%=u.getmId() %>></td> <td><%=u.getmId() %></td> <td><%=u.getusername() %></td> <td><%=u.getpassword() %></td> <td><%=u.getssuper() %></td> <td> <a href="updateUser.jsp?mid=<%=u.getmId() %>">修改</a> <a href="updateUser?f=del&mid=<%=u.getmId() %>" onclick = "return confirm('您确定要删除该条记录吗?');">删除</a></td> </tr> <% }}%>
    结果截图

    4.3.6 统计信息模块
    统计信息模块的部分代码和截图
    Servlet部分代码
    //调用DAO查找所有信息tatalDAO td = new tatalDAO();Vector<Member> v1 = td.tatal1();HttpSession s = req.getSession();s.setAttribute("tatal1", v1);Vector<Member> v2 = td.tatal2();s.setAttribute("tatal2", v2);Vector<Member> v3 = td.tatal3();s.setAttribute("tatal3", v3);//返回到tatal.jsp页面并显示查找到的所有信息resp.sendRedirect(req.getContextPath()+"/admin/tatal.jsp");
    DAO部分代码
    conn = DataAccess.getConnection();prep = conn.prepareStatement("select cName AS 社团," + " COUNT(mName) AS 人数," + " SUM(CASE mGender WHEN '男' THEN 1 ELSE 0 END) AS 男," + " SUM(CASE mGender WHEN '女' THEN 1 ELSE 0 END) AS 女 " + " FROM member " + " GROUP BY cName"); rs = prep.executeQuery();while(rs.next()){ Member m = new Member(); m.setcName(rs.getString("社团")); m.setmName(rs.getString("人数")); m.setmGender(rs.getString("男")); m.setmGender1(rs.getString("女")); v.add(m);
    结果截图

    第五章 总结该社团信息管理系统的构建,首先是在MySQL数据库里创建了一个数据库association,建了三张表:成员表、社团表和活动表,并将他们联系起来。但是后来在准备登录页面的时候,发现三张表可能不够用,所以我创建了第四张表用户表,专门来存储注册登录系统的用户信息。在构建好数据库之后,就开始在javaee中实现对数据库的表的增删改查,创建了定义的DTO,写方法的DAO,还有测试的TEST,还有工具类等等,保障每张表的增删改查都能顺利执行。这些文字写出来好像很顺利,但是在实际操作过程中,我们遇到了各种各样奇葩的错误,完全摸不着头脑。记得有一次就是,本来还好好的,但是系统突然就无法连接上数据库了,一直报错,控制器那里一大片一大片的红色错误,却找不到具体的指示,把错误复制去百度,但是提供的都是各种奇奇怪怪的解决方法,在试过之后也不能解决。真真的耗了整整一天在看一个错,但是后来,第二天打开电脑运行的时候,一点问题都没有。我到现在还是不知道当时是怎么回事,也尝试过关机重启,但是并没有用。
    在完成这些后,我们将程序复制到新建的web文件里面,开始javaweb的应用程序的构建。还记得,第一次使用 http:localhost:8080 页面显示出Hello World!的时候,我们是多么的兴奋,感觉拿到了一车子的棒棒糖。现在看来可能会觉得很简单,但事实是也出了很多错误,调了很久才成功的。切身的体会就是敲代码,做程序真的是很考验一个人的耐心和细心的,你必须要足够细心才能尽量不犯错,发现错误,必须要足够耐心才能一点点的调出错误的地方,解决它。在Javaweb工程中,我构建了WEB.XML等XML文件,还有就是控制只有管理员才能访问的Servlet过滤器filter,让只有管理员才能访问在admin文件目录下面的页面。相当于设置了权限,让普通用户不能访问。还有的就是各式各样的Servlet了,在这个系统里差不多有28个servlet,而且每创建一个servlet就要去web.xml里面配置一次,而且一点都不能有错,每次都写的小心翼翼的。后来我直接创建了Servlet让web.xml自己配置好,但是我之前写的注释会不见,但为了不写错,也只能这样了。Servlet是用来调用方法,把结果返回到jsp页面里面去的。但是我的servlet总会出问题,就是它无法获取到jsp触发的信息,而不能去调用方法,导致传到jsp的数据都是空值,后来和同学讨论了一下,我给每一个jsp需要触发servlet的地方配了一个form action 来调用对应的Servlet。但是还是会出问题,奇奇怪怪的问题,但是我自己一个人想总是找不到问题出在那里,和同学一起想的时候往往就能找到出问题的地方。
    我觉得我何其幸运。每写完一个servlet,我就会开始写它对应的jsp,有时还会有js。就这样大错小错不断,我慢慢完成了这四个表的对应的功能。我的系统主要分为两类用户,一个是普通用户,另一个就是管理员了。普通用户主要是有四个功能模块,一是个人资料,他登录之后就可以打开个人资料界面查看自己的个人资料,后面会有个修改的按钮,他可以修改自己的用户名和密码,但是个人信息的编号和权限被我设定了只读,所以他只能看,不能改。其实就是把他的用户信息从用户表了挑出来,他就是做了用户表的修改而已。二是申请社团,是一个表单,就是做社团表的增添,但是我设了一个标志位,所以需要通过管理员的审核才能实现。三是查看社团和加入社团,就是查看社团表和添加成员表而已,也是通过了标志位,只有通过管理员审核,才能成为会员。四是参看参加了社团的信息,就是把他的成员信息从表里挑出来,后面还有个退出社团的按钮,就是删除成员表一条记录的功能实现。关于管理员的功能模块,主要就是对所有表的增删改查,还有就是统计了。统计是后来新建了一个DAO做的,运用了数据库的语句整合了几张临时表,让系统信息能更直观的显示出来,方便管理员的操作。这些是系统功能的实现,关于页面,是从模板之家copy来的,改掉了标签,添加了一些自己的东西,借用了页面的按钮。然后,我找了个方法,从登录页面获取用户编号来获取用户名,然后把它显示在页面上,这样它就可以成为该用户的个人页面了。
    结果就是完成了还算符合要求的系统,虽然很多很多漏洞,但是在不断解决问题的过程中,我还是收获到了很多快乐,很感谢老师和我的朋友一直没有放弃我。结论就是以后还是要做这一行的,好好加油,坚持把书里的代码都敲它一边,理解一下,要不断的在成长才行。展望的话,我挺想在继续完善这个系统,让它变得更好一点。
    0  留言 2021-09-19 09:50:37
  • 基于SpringBoot+Vue+Redis实现的前后端分离学生宿舍管理系统

    1.项目简介1.1 背景分析随着互联网快速发展,电脑的发展,让我们的生活更加的便利,也在学校的办公管理领域得到了很好发挥,以前记录学生宿舍操作需要通过人工记录的方式,来登记,这样的操作极其不方便,尤其是在查阅某个人员进出时的情况,需要查看过多的人员信息,这对工作造成了极不方便,所以开发一套学生宿舍管理系统,就可以很好的解决这一难题。
    通过使用学生宿舍管理系统不仅可以降低人工成本,而且在管理上也可以得到很好的提升。以前在宿舍记录管理中,最容易出错的环节,就是登陆人员的进出情况,而该系统软件的出现,可让更多的时间花在如何管理信息化,让信息化得到更快捷的服务。本系统结合业务需求,及线下宿舍管理操作流程,量身定制一款学生宿舍管理软件。主要解决快速查找人员宿舍管理等实用性功能,主要是基于Web网页开发的一个宿舍管理系统。
    1.2 课题研究现状在和现有的学生宿舍管理系统进行比较后,发现了许多问题:
    系统功能并不全面。很多学校的学生宿舍管理系统的功能模块并不全面,有些系统只有最基本的宿舍共用电器或者物品的上报维修和用户信息管理功能,但是只是这样是远远不够的,来访人员如果要来看望某位学生,系统没有此功能的话,依然需要人力手工记录以及查询被看望学生的基本信息。有些学校的宿舍管理系统没有宿舍的基本信息,有时候就无法及时了解到该宿舍是否入住满员,还是只是住了一部分。还有的宿舍管理,没有对宿舍环境进行一个打分操作,对宿舍的环境分数进行排序来选出最优宿舍,还可以找出分数最低的几个宿舍进行一个需改良宿舍的选择。
    国外只有少数学校可以达到,外国学生进出宿舍刷卡并且同时人脸识别进行人卡相匹配。这是我们暂时无法解决的问题,一个是外国的宿舍设施原本就配有一些电子产品,在后续的更新迭代中就显得容易些,还有一个就是外国的信息发展团体多。宿舍管理系统能够越来越普及的原因还是高校的数量激增,人工记录难以应对大量的学生信息。
    我的课题借鉴了上述宿舍共用电器上报维修和用户信息管理之外,还添加了来访人员登记以及对学生宿舍的环境打分和排序。和我们学校宿舍的手写公告不同,我还增加了一栏专门用于公告提示。
    1.3 课题主要研究内容本课题是一个学生宿舍管理系统。具体研究内容如下:
    技术上采用springboot集成快速开发框架,前端使用vue方式,基于es5的语法,开发工具IntelliJ IDEA 2020.1.1 x64,因为该开发工具,内嵌了Tomcat服务运行机制,可不用单独下载Tomcat server服务器。
    功能上用户信息管理功能、房间信息管理功能、来访信息管理功能、物品报修管理功能、维修进程管理功能、公告信息管理功能等。
    学生能够查看自己的个人信息,对宿舍公用电器可以进行一个报修,能查看维修的进程。管理员可以进行公告布置,修改密码,对维修进程的状态进行更改,对系统用户和日志的管理。
    1.4 功能模块随着每年高校大学生不断的扩招,人数的增加导致宿舍管理压力巨大。学校宿舍作为高校管理的组成部分,现如今还有部分高校,通过纸质的方式登记学生进出宿舍的情况,这不仅工作效率低下,而且使得的管理上也极其反映当时的情况,尤其在查询数据时,会相当的繁琐,偶尔可能会存在表单记录丢失的情况,所以,很有必要推出一款便于学生宿舍管理的一套软件。
    本系统主要采用spring开发框架制。使用的技术有mysql数据库、mybatis驱动框架以及tomcat服务端部署,用到的集成开发工具主要是IDEA和jdk1.8。
    该学生宿舍管理系统主要有以下几大功能:个人中心、学生管理、宿舍信息管理、请假记录管理、维修记录管理、公告信息管理、用户管理、日志管理
    2.开发工具2.1 IntelliJ IDEAIntelliJ IDEA是用于Java语言开发的集成环境,是公认的最好的Java开发工具之一,IDEA相较于其他Java开发工具,具有智能选取、历史记录功能、编码辅助、排版灵活、与文件系统自动同步、代码检查、完全支持JSP等优势。
    2.2 TomcatTomcat服务器是一个免费的、开源的轻量级Web应用服务器,是开发和调试JSP程序的首选,Tomcat运行时占用的系统资源小,建有良好的可扩展性和安全性。
    2.3 MySQLMySQL是一款安全的、跨平台的、高效的、与主流编程语言紧密结合的数据库系统,MySQL由于其体积小、速度快、总体拥有成本低、开源等特点,广泛适用于中小型网站的开发,在Web应用方面,MySQL是最好的RDBMS(关系数据库管理系统)应用软件之一。
    2.4 开发技术2.4.1 Vue不断繁荣的生态系统,可以在一个库和一套完整框架之间自如伸缩。
    2.4.2 RedisRedis是一个开源的使用ANSIC语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
    2.4.3 Spring BootSpring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。
    Spring Boot特点

    创建独立的Spring应用程序
    嵌入的Tomcat,无需部署WAR文件
    简化Maven配置
    自动配置Spring
    提供生产就绪型功能,如指标,健康检查和外部配置
    绝对没有代码生成和对XML没有要求配置

    3.系统分析3.1 可行性分析在系统开发的过程中系统的可行性分析是必不可少的,可行性的研究就是评估问题是否能得到解决并且是要以最少的时间和最少的代价来解决。为实现上面的目标还要必须考虑到解决这些问题的方法的优点和缺点,还要考虑到实现了这些系统规模的开发带来的经济效益。这里可以用技术的可行性,操作的可行性,经济的可行性对我们的系统进行可行性的研究。
    3.1.1 技术性可行性本项目设计的系统主要采用layui前端开发,后端使用java语言以及springboot集成开发性框架,采用mysql数据库,根据自身所学专业,结合网上查阅案列及图书馆资料,开发实现是没有太大问题的。
    3.1.2 经济性可行性开发一套成熟的软件,都需要经过一段漫长的过程,这里设计到软件的需求分析、制定计划,开发人员、测试环节、调试过程,都需要资金及人力的投入。而这套软件的开发,可以通过网上开源源码及相关资料的学习,在硬件及电脑使用上,都是自己所用,所以在开发成本上可以忽略不计。
    3.1.3 操作性可行性本系统设计到的功能主要有个人中心、学生管理、房间信息管理、来访信息管理、物品报修管理、维修进程管理、公告信息管理,这些功能模块的相关知识,都是平常所设计到的常用功能,在操作上都是可以实现的。
    3.2 系统需求分析通过了解用户的需求,可以知道操作简单的系统更易受到用户青睐,同时能够准确、完整的对信息进行管理。学生宿舍管理平台在对需求做相应的分析后,得出结论,系统主要分为两个角色:管理员和学生用户。管理员模块主要进行数据的更新管理,功能分为个人中心、学生管理、房间信息管理、来访信息管理、物品报修管理、维修进程管理、公告信息管理;学生模块主要功能有个人中心、房间信息管理、来访信息管理、物品报修管理、维修进程管理、公告信息管理及评分信息管理。
    3.2.1 功能需求本系统是利用现代化的计算机网络技术将传统信息宣传方式整合,按照实践过程设计完成的。同时完善服务,初步设计一个学生宿舍管理系统平台以利于相关的事务操作。为了使系统在各项管理中发挥更大的作用,实现计算机信息化高效的管理,现将开发目标功能需求介绍如下:
    管理员登录模块
    管理员有权进行学生宿舍系统的管理,但所有的注册以及权限的使用,都需经过超级管理员授权,管理员进入主页后可以对相关功能版块进行管理操作:个人中心、学生管理、房间信息管理、来访信息管理、物品报修管理、维修进程管理、公告信息管理。

    学生管理模块
    拥有一定管理权限管理员,可进行学生列表的用户名称、用户密码、性别、学号、电话、相片、所在寝室查看,以及对应的学生增加、删除、修改、查询操作。

    宿舍管理模块
    拥有一定管理权限管理员,可进行宿舍列表的房间号、房间类型、楼层号、宿舍设备、校园图片、床位数量、登记时间查看,以及对应的宿舍增加、删除、修改、查询操作。

    物品报修管理模块
    拥有一定管理权限管理员,可进行物品报修列表的数据查看,以及对应的物品报修增加、删除、修改、查询操作。

    3.2.2 非功能需求该系统不仅要满足功能性需求,还需要满足看不到的非功能性需求,比如系统的兼容性、用户界面整体性、网页访问的流畅性,主要归纳如下几点:

    支持兼容性多浏览器访
    界面性网站整体美观、元素搭配协调
    安全性访问控制不受到攻击,防止sql注入

    4.系统总体设计4.1 系统功能图该项目管理系统主要基于B/S设计模式,系统设计的功能有:学生管理、房间信息管理、来访信息管理、物品报修管理、维修进程管理、公告信息管理等。

    4.2 系统流程图学生宿舍管理系统工作流程为:当用户输入账号和密码,可登陆到系统的控制台页面,控制台可以对学生管理、房间信息管理、来访信息管理、物品报修管理、维修进程管理、公告信息管理进行数据库操作,执行完成后,可直接退出系统。以下是总体的流程图设计

    4.3 数据库设计4.3.1 表结构用户表

    权限表

    日志表

    学生表

    宿舍表

    宿舍楼表

    公告板

    班级表

    留言评论表

    4.3.2 E-R图
    4.4 项目开发@RestController@RequestMapping("/system/user")public class SystemUserController { @Autowired private SystemUserService systemUserService; @Autowired private RedisUtil redisUtil; @PostMapping("/list") @RequirePermission(permissions = {"system:user:list"}) public Result<PageInfo<SystemUser>> list(@RequestBody ListQuery<SystemUser> listQuery) { //多对多查询,先获取符合条件的id,否则pageInfo中的数据会出错 List<Long> ids = systemUserService.listIdFitCondition(listQuery.getEntity()); PageHelper.startPage(listQuery.getPage(), listQuery.getRows()); List<SystemUser> list = systemUserService.listByIds(ids); PageInfo<SystemUser> pageInfo = new PageInfo<>(list); return Result.<PageInfo<SystemUser>>ok().add(pageInfo); } @GetMapping("/query") @RequirePermission(permissions = {"system:user:query"}) public Result<SystemUser> query(@RequestParam("id") Long id) { SystemUser systemUser = systemUserService.get(id).orElseThrow(() -> new HttpException(HttpCode.FAILED, "没有该用户")); return Result.<SystemUser>ok().add(systemUser); } @GetMapping("/delete") @RequirePermission(permissions = {"system:user:delete"}) @Log("删除用户") public Result<?> delete(@RequestParam("id") Long id) { List<SystemUser> subordinates = systemUserService.listByLeaderId(id); if (subordinates.size() > 0) { throw new HttpException(HttpCode.FAILED, "该用户为其他人领导,无法删除"); } else { systemUserService.delete(id); return Result.ok("删除成功"); } } @PostMapping("/saveOrUpdate") @RequirePermission(permissions = {"system:user:save", "system:user:update"}) @Log("添加修改用户") public Result<?> saveOrUpdate(@RequestBody @Validated SystemUser user) { Boolean validate = systemUserService.validateLoginName(user.getLoginName(),user.getId()); if (!validate) { throw new HttpException(HttpCode.FAILED, "登录名称已存在"); } systemUserService.saveOrUpdate(user); return Result.ok("操作成功"); } @GetMapping("/resetPassword") @RequirePermission(permissions = {"system:user:update"}) @Log("重置用户密码") public Result<?> resetPassword(@RequestParam("id") Long id) { systemUserService.changePassword(Constant.DEFAULT_PASSWORD, id); return Result.ok("密码重置成功"); } @GetMapping("/listAll") @RequirePermission(permissions = {"system:user:list"}) public Result<List<SystemUser>> list() { List<SystemUser> systemUserList = systemUserService.listAll(); return Result.<List<SystemUser>>ok().add(systemUserList); } /** * 修改密码 * * @param token token * @param password 包括原密码,修改后的密码,再次输入的密码 * @return 密码是否修改成功 */ @PostMapping("/change") public Result<?> validate(@RequestHeader(HEADER_TOKEN) String token, @RequestBody Password password) { if (!password.getCurrent1().equals(password.getCurrent2())) { throw new HttpException(HttpCode.FAILED, "两次密码输入不一致"); } Long id = redisUtil.get(token); Boolean bool = systemUserService.validatePassword(password.getOldPassword(), id); if (bool) { systemUserService.changePassword(password.getCurrent1(), id); //移除token redisUtil.deleteToken(token); return Result.ok("密码修改成功,请重新登录"); } else { throw new HttpException(HttpCode.FAILED, "原密码不正确"); } } /** * 修改登录用户信息 * * @param systemUser 修改的用户 * @return 修改成功后将修改后的用户返回 */ @PostMapping("/update") public Result<SystemUser> update(@RequestBody SystemUser systemUser, @RequestHeader(HEADER_TOKEN) String token) { systemUser.setId(redisUtil.get(token)); systemUserService.saveOrUpdate(systemUser); return Result.<SystemUser>ok("修改成功").add(systemUser); } @GetMapping("/changeIcon/{icon}") public Result<?> changeIcon(@PathVariable String icon , @RequestHeader(HEADER_TOKEN) String token) { systemUserService.changeIcon(icon, redisUtil.get(token)); return Result.ok("修改成功"); }}
    5.项目展示登录

    宿舍管理

    权限菜单管理

    修改菜单


    角色管理

    修改角色

    班级管理


    6.总结遇到的问题:

    分用户登录之后的权限问题
    一对多查询问题

    解决方案

    分用户登录之后的权限问题

    对于这个问题本来是想通过SpringSecurity来写的,但是水平不够,没写出来,后来就用了笨方法,通过单选框实现分用户登录,之后的所有功能无论是相同的还是不同的都分用户身份写
    mybatis一对多查询问题

    在项目实现过程中,多处用到了一对多查询,而这个问题也是我写这篇博客的主要原因,因此叙述的会稍微详细一些持久层我使用的是mybatis,数据库使用的是mysql,查询用的是左外连接
    0  留言 2021-09-19 09:30:46
  • 基于Springboot+RabbitMQ+redis实现的超市订单管理系统

    1 系统需求分析超市订单管理系统是一个专为连锁店、超市等商业场所提供订单管理平台的系统。该系统的目标是建立一个订单管理平台,为需要合理规划超市供应链、供应商以及工作人员提供的便捷的平台。该系统的主要业务需求包括记录并维护某超市的供应商信息,以及该超市与供应商之间的交易订单信息,包括三种角色,系统管理员,经理,普通员工。
    1.1 系统功能分析本系统主要的功能是实现超市订单管理功能,以便为超市、连锁店提供以及其他负责人提供订单详情、联系方式等,系统的主要功能有以下五个方面:

    登录/注销:管理员可以在网站上登录浏览,离开时注销并退出
    订单管理:管理员可以浏览所有订单信息,并且通过点击查看了解订单详情信息
    供应商管理:管理员可以在网站浏览所有供应商信息,并在在与其他供应商达成合作之后,添加相关供应商信息,并且通过点击查看了解他们的联系方式等
    用户管理:管理员可以管理所有超市员工用户,对用户进行增删改查,对于离职或其他原因的未工作用户给予注销管理
    密码修改:管理员可对自己的账号密码进行修改,填写对应之前的正确密码以及新密码之后,即完成相关修改密码操作
    搜索功能:在以上管理界面中,均允许了管理员根据关键字进行搜索,要求搜索框中输入的字段必须完全包含在物品名称中,否则无法查询


    1.2 系统功能需求根据系统功能要求,该超市订单管理系统以管理员为中心的用户角色,可以将系统分解成几个模块来分别设计应用程序界面,如图 1.1所示。

    1.3 系统性能需求超市订单管理系统的开发是在Window10平台上,以Springboot+RabitMQ为架构,采用MySQL 作为数据库管理系统管理后台数据库。本系统是超市信息管理建设中必不可少的一部分,它实现了现代管理信息系统的大部分功能需要。使用本系统可以使超市管理更加方便快捷,合理的页面设计也使得这个用户充分享受到基于Internet管理信息系统的优越。本系统开发说明:
    功能完备
    在开发初期,查看了大量关于电子商务,管理信息系统,J2EE等方面的资料,同时借鉴了很多其他电子商务网站和管理信息的流程。经过总结,确定了满足需求分析的基本模块。系统总体设计上实现了整个系统模块的划分,系统主要包含5大模块,分别是:订单管理信息,供应商管理,用户管理,修改密码,登陆退出系统,基本上实现了综合管理系统的所有功能。
    界面友好
    系统用户登陆到管理页面后,每页有导航和引领的作用。系统具有自适应的能力,同时导航条方便快捷的引导用户进行各种合理的操作。
    管理科学
    本系统一开始就从管理学的角度做出了详细细致的考虑,后来有参考了电子商务管理等,最后才做出了系统总体设计,因此可以讲该系统是较为科学的。
    系统的性能需求主要表现在数据库中的各个表需要频繁地被插入、删除以及更新。对于用户来说,系统地响应时间不宜太长,否则会降低用户体验。为此要求我们建立良好的表结构,加上足够的存储空间以及硬件性能。
    2 可行性分析2.1 研究前提随着我国经济情况的日新月异,飞速发展,涌现出许许多多的超市和便利店。越来越多的人喜欢到超市购物,超市里销售的商品也呈现出多种多样的变化趋势。我们开发一个超市订单管理系统,它可以对仓储各环节实施全过程控制管理,对整个进货、退货、盘点等各个环节的规范化作业,控制整个过程的正常运行。去掉了手工书写票据和送到机房输入的步骤,解决库房信息陈旧滞后的弊病,方便了仓库管理人员对物品的放置和调配,提高了工作效率。
    该系统容易被接受,具有简单易学性,便于管理等功能,是对超市订单管理的一种有效工具。
    2.2 设计要求2.2.1 安全性超市订单管理增强对产品规范的审计,重点确定该项目中需要审计的产品。买家只能针对卖家允许公开的信息进行查阅。买家只享受对自己账号内数据的查阅权,与定后处理权,订货支付权,申请退货权,不允许偷窥其他人。卖家只能针对买家允许公开的信息进行查阅。卖家只享受对自己账号内数据的查阅权,发货权,退款相应处理权,不允许偷窥其他人。
    2.2.2 系统性能管理员登录查看超市供应商与超市员工用户管理,可以进行增、删、改、查等操作。超市订单系统可以使超市的管理趋于正规化、现代化和系统化。本项目的产品可以达到以下目标:

    提高工作效率,减少返工
    业务流程的流水线化
    符合相关标准和规则
    与目前的应用产品相比较,提高了可用性或减少了失效程度

    2.2.3 可扩展性所有信息呈现,操作完全由打开的网页呈现并完成。本系统所占有的是超市市场,它追求的是简单、易学、易用,能够更好地解决管理人员的负担,能够辅助超市有效的管理物品。对于订单管理系统的用户,可满足对订单管理的需求,且此种需求被接受并且满足,其系统便可以推广。
    3 数据库设计3.1 数据库需求分析经过对超市管理系统的调查分析,得出用户的需求大致如下:

    管理员可以在系统中对订单、供应商以及用户进行增、删、改、查的处理
    管理员需要输入账号密码登录,并且可以增添新的管理员

    如下是利用数据流图方法对数据库做需求分析:
    第一步:由用户的需求,可以得到顶层数据流图如图

    第二步:超市订单管理系统的第1层数据流图如图所示。

    第三步:超市订单管理系统的第2层数据库流图——订单管理的细化数据流图如图所示。

    第四步:超市订单管理系统的第2层数据流库——供应商管理的细化数据流图如图所示。

    第五步:超市订单管理系统的第2层数据流库——用户管理的细化数据流图如图所示。

    根据如上的数据流程图,可以列出以下记录超市订单管理所需的数据项和数据结构:

    管理员:管理员ID、管理员姓名、管理员密码、管理员性别、管理员角色、管理员出生日期、管理员电话、管理员住址
    订单:订单编码、商品名称、供应商名称、订单金额、是否付款
    供应商:供应商编码、供应商名称、联系人、联系电话、微信

    3.2 数据库概念结构设计本系统一共有用户、供应商、订单、角色、地址这五个基本实体。
    管理员可以对应多个订单,而一个订单只能对应于一个管理员。管理员可以管理多个供应商,而一个供应商只能对应于一个管理员。一个供应商可以对应多条订单,但一条订单只能对应于一个供应商。此外,有一个用户对应一个角色,一个角色对应多个用户;一个地址对应多个订单,一个订单对应一个地址。数据库表之间的关系如下:


    用户:主键ID、用户编码、用户名称、用户密码、性别、出生日期、手机、地址、用户角色、创建者、创建时间、更新者、更新时间、用户头像、工作照
    账单:订单编号、订单编码、商品名称、商品描述、商品单位、商品数量、商品总额、是否支付、创建者、创建时间、更新者、更新时间、供应商ID
    供应商:供应商ID、供货商编码、供货商名称、供应商详细描述、供应商联系人、联系电话、地址、微信、创建者、创建时间、更新时间、更新者、营业执照、组织机构代码证
    地址:主键ID、联系人姓名、收货地址明细、邮编、联系人电话、创建者、创建日期、修改者、修改时间、用户ID
    角色:角色编号、角色编码、角色名称、创建者、创建时间、修改者、修改时间

    3.2 表结构用户表

    权限表

    供应商表

    商品表

    收货地址表

    3.3 逻辑结构设计
    4 各功能模块的设计与实现4.1 系统开发条件4.1.1 开发语言系统使用的开发语言是Java。Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程等特点。Java可以编写桌面应用程序、Web应用程序、分布式系统应用程序等。正是因为Java语言拥有如此诸多的优秀特性,所以我们选择了它作为开发超市订单管理系统,使得整个开发、调试过程更加高效。
    4.1.2 开发框架超市订单管理系统以Springboot架构作为支撑,分为表现层、业务层和持久层三层,实现后台数据更新。该架构由Spring MVC、Spring和MyBatis三个开源框架整合而成,用于开发结构合理,性能优越,代码健壮的应用程序,其次采用了消息中间件RabbitMQ和Redis做高并发缓存处理机制。
    4.1.3 前端框架由于本系统是Web应用,所以使用了HTML5+CSS3+JavaScript的方式实现前端页面。实现过程中参考了Bootstrap前端开发框架。Bootstrap是Twitter退出的一个用于前端开发的开源工具包。在设计前端页面时,参考了Bootstrap的相关开源代码。
    4.1.4 集成开发环境编程所使用的集成开发环境是Eclipse,是著名的跨平台的自由集成开发环境(IDE)。Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。本次系统便选用了Eclipse作为开发平台。
    4.1.5 Web应用服务器Tomcat由Apache、Sun和其他一些公司及个人共同开发而成。由于有了Sun的参与和支持,最新的Servlet和JSP规范可以在Tomcat中得到体现。因为Tomcat技术先进、性能稳定,因而成为目前比较流行的Web应用服务器。本次系统选用的便是Tomcat作为应用服务器。
    4.1.6 数据库管理系统本系统使用的数据库管理系统是MySQL Community。MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发。在WEB应用方面,MySQL是最好的RDBMS (Relational Database Management System,关系数据库管理系统)应用软件。
    系统中的数据库以及数据库中的所有关系模式都使用MySQL进行处理。
    4.2 用户界面设计完成数据库创建和功能说明以后,我们进行下一步工作,即设计用户界面,完成了系统要求的 5 项主要功能。
    我们把超市订单管理系统的窗体分成5个主要部分,如下图所示。
    订单管理

    供应商管理

    用户管理

    修改密码

    登录注销

    4.3 功能模块说明4.3.1 订单信息添加、查询、修改与删除订单信息查看
    为了对订单浏览信息,能够实现浏览的功能是十分必要的。管理员输入需要搜索的相应信息,点击查看按钮后系统将寻找到的数据展示到网页中。

    订单信息添加
    作为超市订单管理系统,订单信息的管理是很重要的。每当采购部门增加新的订单时,订单信息就要增加。超市也可能因为其它原因增加订单信息,订单添加模块都可以做出快捷的解决方案。管理员输入相应的信息,点击提交后系统将数据保存到数据库中。

    订单信息修改
    根据订单编号可以查询订单详细信息,然后修改订单的所有信息。系统从数据库中读取数据并显示到页面上,管理员修改数据后,点击修改按钮,系统将更新表中的数据。

    订单信息删除
    根据订单编号可以删除该订单的信息。管理员选择需要删除订单名称并点击删除按钮,系统将从数据库中删除相应数据。

    订单信息查询
    在成千上万种商品种,如果人为寻找某一个商品肯定是不可能的,只有通过商品信息查询模块才能为用户或管理人员解决这个难题。根据订单名称可以查询该订单的信息。管理员输入订单名称并点击查询按钮,系统将从数据库中查询相应的数据并显示到页面上。

    4.3.2 供应商信息添加、查询、修改与删除供应商查询界面
    供应商查询界面提供了供应商的信息,可根据供应商名称的关键字进行筛选查询,并提供了添加供应商、查看供应商详细信息、修改供应商信息、删除供应商的功能。

    供应商查看详情界面
    在供应商查询界面点击具体供应商操作列表的查看按钮,可以查看供应商的具体信息,包括:供货商编码、供货商名称、详细描述、联系人、联系电话、地址、微信。

    供应商修改页面
    若供应商信息变动,管理员可通过供应商信息修改功能对供应商信息进行更新,更新后的数据将保存到数据库中。

    商品供应商信息删除
    企业倒闭或者经营策略的改变,当它对超市商品的供应没有作用时,商品供应商厂家信息的删除是正常的。管理员输入供应商名称查询数据表中的数据并显示到页面上,点击删除后系统将表中的相应数据删除。

    供应商添加界面
    与供应商达成交易后,管理员在供应商添加页面填写供应商具体信息,填写完毕点击提交,添加后的数据将保存到数据库中。

    4.3.3 用户信息添加、查询、修改与删除用户管理页面
    通过输入用户名和身份查询用户。当不记得用户名的具体名字时,只输入用户名的其中一个字,会检索出所有带这个字的用户,方便管理员查询管理。点击右边链接添加用户,会连接到相关网页添加用户信息。点击操作里的查看、修改等可以进行相应的改、删、查操作。

    用户信息删除
    当企业员工离职时,或者经过一段时间后,会发现用户表中一些信息时无用的,用户删除模块可以解决这样的问题。

    添加用户信息
    填写用户相关信息,下面有两个按钮,可以选择重置或者提交。

    修改密码
    为了系统的安全,用户的应该只有用户个人才能修改,这不仅保证了整个公司的利益也保护了个人隐私。用户在输入相应的用户编号,填写旧密码以及新密码后,点击提交,重置密码成功。发现输入错误时,可以手动删除或者点击重置按钮,重新填写。

    修改用户密码成功后,会弹出修改用户密码成功页面,如图所示。

    4.3.4 登录/注销输入用户名以及用户密码登录进入超市订单管理界面,可以查看管理信息。管理员可以对相关数据进行增、改、查等操作,也可以注销退出系统。
    4.4 功能实现部分代码
    @Controllerpublic class Page_jump { //表示方法与请求URL的映射,这里映射/index请求 @RequestMapping(value="/billadd",method = {RequestMethod.POST, RequestMethod.GET}) public String billadd(){ return "billadd"; } @RequestMapping(value="/pwdmodify",method = {RequestMethod.POST, RequestMethod.GET}) public String pwdmodify(){ return "pwdmodify"; } @RequestMapping(value="/provideradd",method = {RequestMethod.POST, RequestMethod.GET}) public String provideradd(){ return "provideradd"; } @RequestMapping(value="/useradd",method = {RequestMethod.POST, RequestMethod.GET}) public String useradd(Model model){ model.addAttribute("user", new User());//这里给视图层提供了数据的对象,用来数据绑定 return "useradd"; } @RequestMapping(value="/pwdmodify.do",method = {RequestMethod.POST,RequestMethod.GET}) public String index(){ return "pwdmodify"; } @RequestMapping(value="/pwdmodify.do",method = {RequestMethod.POST,RequestMethod.GET}) public String index(){ return "pwdmodify"; } @RequestMapping(value="/pwdmodify.do",method = {RequestMethod.POST,RequestMethod.GET}) public String index(){ return "pwdmodify"; } @RequestMapping(value="/pwdmodify.do",method = {RequestMethod.POST,RequestMethod.GET}) public String index(){ return "pwdmodify"; } @RequestMapping(value="/pwdmodify.do",method = {RequestMethod.POST,RequestMethod.GET}) public String index(){ return "pwdmodify"; } //@RequestMapping(value="/test2",method = {RequestMethod.POST,RequestMethod.GET}) @RequestMapping(value="/index1") public ModelAndView index1(@RequestParam(value="username",required = false) String username){ ModelAndView mav= new ModelAndView(); mav.addObject("username",username); mav.setViewName("index"); return mav; } @RequestMapping(value="/index2") public String index2(@RequestParam(value="username",required = false) String username, Model model){ model.addAttribute("username",username); return "index2"; } @RequestMapping(value="/index3") public String index3(@RequestParam(value="username",required = false) String username, Map<String,Object> model){ model.put("username",username); return "index2"; }}
    @Controller@Api("Provider验证接口")public class ProviderServlet { @Autowired BillServiceImpl billService; @Autowired ProviderServiceImpl providerService; @Autowired UserServiceImpl userService; @RequestMapping(value="/provider.do",method = {RequestMethod.POST, RequestMethod.GET}) public String doPost(HttpServletRequest request, HttpServletResponse response, @RequestParam(value="method",required = false) String method) throws ServletException, IOException { if(method != null && method.equals("query")){ return this.query(request,response); }else if(method != null && method.equals("add")){ return this.add(request,response); }else if(method != null && method.equals("view")){ return this.getProviderById(request,response,"providerview"); }else if(method != null && method.equals("modify")){ return this.getProviderById(request,response,"providermodify"); }else if(method != null && method.equals("modifysave")){ return this.modify(request,response); }else if(method != null && method.equals("delprovider")){ this.delProvider(request,response); } return "error"; } private void delProvider(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String id = request.getParameter("proid"); HashMap<String, String> resultMap = new HashMap<String, String>(); if(!StringUtils.isNullOrEmpty(id)){ int flag = providerService.deleteProviderById(id); if(flag == 0){//删除成功 resultMap.put("delResult", "true"); }else if(flag == -1){//删除失败 resultMap.put("delResult", "false"); }else if(flag > 0){//该供应商下有订单,不能删除,返回订单数 resultMap.put("delResult", String.valueOf(flag)); } }else{ resultMap.put("delResult", "notexit"); } //把resultMap转换成json对象输出 response.setContentType("application/json"); PrintWriter outPrintWriter = response.getWriter(); outPrintWriter.write(JSONArray.toJSONString(resultMap)); outPrintWriter.flush(); outPrintWriter.close(); } private String modify(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String proContact = request.getParameter("proContact"); String proPhone = request.getParameter("proPhone"); String proAddress = request.getParameter("proAddress"); String proFax = request.getParameter("proFax"); String proDesc = request.getParameter("proDesc"); String id = request.getParameter("id"); Provider provider = new Provider(); provider.setId(Integer.valueOf(id)); provider.setProContact(proContact); provider.setProPhone(proPhone); provider.setProFax(proFax); provider.setProAddress(proAddress); provider.setProDesc(proDesc); provider.setModifyBy(((User)request.getSession().getAttribute(Constants.USER_SESSION)).getId()); provider.setModifyDate(new Date()); boolean flag = false; flag = providerService.modify(provider); System.out.println("--------flag="+flag); if(flag){ return "redirect:/provider.do?method=query"; }else{ return "providermodify"; } } private String getProviderById(HttpServletRequest request, HttpServletResponse response, String url) throws ServletException, IOException { String id = request.getParameter("proid"); System.out.println("-------------"+id); if(!StringUtils.isNullOrEmpty(id)){ Provider provider = null; provider = providerService.getProviderById(id); request.setAttribute("provider", provider); System.out.println("-------------"+id); return url; } return "error"; } private String add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String proCode = request.getParameter("proCode"); String proName = request.getParameter("proName"); String proContact = request.getParameter("proContact"); String proPhone = request.getParameter("proPhone"); String proAddress = request.getParameter("proAddress"); String proFax = request.getParameter("proFax"); String proDesc = request.getParameter("proDesc"); Provider provider = new Provider(); provider.setProCode(proCode); provider.setProName(proName); provider.setProContact(proContact); provider.setProPhone(proPhone); provider.setProFax(proFax); provider.setProAddress(proAddress); provider.setProDesc(proDesc); provider.setCreatedBy(((User)request.getSession().getAttribute(Constants.USER_SESSION)).getId()); provider.setCreationDate(new Date()); boolean flag = false; flag = providerService.add(provider); if(flag){ return "redirect:/provider.do?method=query"; }else{ return "provideradd"; } } private String query(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String queryProName = request.getParameter("queryProName"); String queryProCode = request.getParameter("queryProCode"); if(StringUtils.isNullOrEmpty(queryProName)){ queryProName = ""; } if(StringUtils.isNullOrEmpty(queryProCode)){ queryProCode = ""; } List<Provider> providerList = new ArrayList<Provider>(); providerList = providerService.getProviderList(queryProName,queryProCode); request.setAttribute("providerList", providerList); request.setAttribute("queryProName", queryProName); request.setAttribute("queryProCode", queryProCode); return "providerlist"; }}
    5 实训总结5.1 所遇困难在实现本系统时遇到的困难主要体现在两个方面,一是系统的前端页面的设计,二是怎样Web与数据库实现交互。
    系统前端页面的设计困难的解决是通过参考著名的前端框架Bootstrap实现的。Bootstrap框架提供了许多精美的组建、布局,还开放了源代码供参考。在此基础上我们还加入了一些利用JavaScript代码实现的美化效果,使得前端设计更加美观。
    实体Web与数据库交互的解决得益于SSM框架的三层Spring MVC、Spring和MyBatis,能够分离处理数据库与Web层的视图,从而达到交互的目的。
    此外,在编写后端的时候,变量的大小写、系统配置也是困难重重。好在,在反复编写之后,迅速熟悉的技巧,能够让页面自由切换。系统配置更是反复在网上求证,得以解决。
    5.2 实验心得这一次合作开发超市订单管理系统,从开始选择课题的困惑到最终完成了一个我们还算满意的作品,使我学到了很多东西。从设计数据库到编写后台代码,链接数据库,在网页上显示,令人印象深刻。反复查阅资料,启动Tomcat到凌晨0点,都是藏着对这次项目的努力。其实,从一开始选择哪个题目是否用SSM框架来开发我一直也犹豫过,像国内势头正旺的ThinkPHP,易学易用,完善的中文开发文档,遇到问题或者bug可以非常容易的在中文社区得到解答。但是我最后选择了SSM框架,不仅仅因为它广泛,而是我希望能够挑战自己。经过这一个周的磨练,我最大的收获除了学到了真正可以应用的知识外,更重要的是学会了项目合作开发的经验。
    0  留言 2021-09-18 11:22:54
  • 基于Springboot和Vue实现的图书管理系统

    1.项目简介1.1 前言由于课设需要做这个,于是就抽了点闲余时间,写了下,基本全部都涉及到,包括书籍信息的更新,查看所有的书籍。这篇我讲一下我的思路以及中间遇到的问题和解决办法。
    1.2 需求分析MIS最重要的就是需求分析,只有分析清晰了,才能动手编程,所谓编程,不过是把一种思路用代码实现而已,这里就图书管理系统来说,这个系统至少要完成如下内容:

    图书信息的增加与删除
    图书信息的更新
    全部书籍的查看

    我说的以上只是最基础的东西,如果能实现的更多当然更全面,就看自己对这个图书管理系统功能的理解了。
    1.3 数据库表的建立当需求分析完成之后,我们要考虑的就是这些信息如何存储在表里,需要几张表,每张表存储什么信息,字段名是什么,什么类型;在这里,我认为只用一张表,用来存储书籍的有关信息。

    搭建数据库
    DROP TABLE IF EXISTS `book`;/*!40101 SET @saved_cs_client = @@character_set_client */; SET character_set_client = utf8mb4 ;CREATE TABLE `book` ( `id` int(10) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, `author` varchar(20) DEFAULT NULL, `publish` varchar(20) DEFAULT NULL, `pages` int(10) DEFAULT NULL, `price` float(10,2) DEFAULT NULL, `bookcaseid` int(10) DEFAULT NULL, `abled` int(10) DEFAULT NULL, PRIMARY KEY (`id`), KEY `FK_ieh6qsxp6q7oydadktc9oc8t2` (`bookcaseid`), CONSTRAINT `FK_ieh6qsxp6q7oydadktc9oc8t2` FOREIGN KEY (`bookcaseid`) REFERENCES `bookcase` (`id`)) ENGINE=InnoDB AUTO_INCREMENT=119 DEFAULT CHARSET=utf8;/*!40101 SET character_set_client = @saved_cs_client */;---- Dumping data for table `book`--LOCK TABLES `book` WRITE;/*!40000 ALTER TABLE `book` DISABLE KEYS */;INSERT INTO `book` VALUES (1,'解忧杂货店','东野圭吾','电子工业出版社',102,27.30,9,1),(2,'追风筝的人','卡勒德·胡赛尼','中信出版社',330,26.00,1,1),(3,'人间失格','太宰治','作家出版社',150,17.30,1,1),(4,'这就是二十四节气','高春香','电子工业出版社',220,59.00,3,1),(5,'白夜行','东野圭吾','南海出版公司',300,27.30,4,1),(6,'摆渡人','克莱儿·麦克福尔','百花洲文艺出版社',225,22.80,1,1),(7,'暖暖心绘本','米拦弗特毕','湖南少儿出版社',168,131.60,5,1),(8,'天才在左疯子在右','高铭','北京联合出版公司',330,27.50,6,1),(9,'我们仨','杨绛','生活.读书.新知三联书店',89,17.20,7,1),(10,'活着','余华','作家出版社',100,100.00,6,1),(11,'水浒传','施耐庵','三联出版社',300,50.00,1,1),(12,'三国演义','罗贯中','三联出版社',300,50.00,2,1),(13,'红楼梦','曹雪芹','三联出版社',300,50.00,5,1),(14,'西游记','吴承恩','三联出版社',300,60.00,3,1);/*!40000 ALTER TABLE `book` ENABLE KEYS */;UNLOCK TABLES;
    1.4 前后端分离前后端分离就是将⼀个应⽤的前端代码和后端代码分开写,为什么要这样做?如果不使⽤前后端分离的⽅式,会有哪些问题?
    传统的 Java Web 开发中,前端使⽤ JSP 开发,JSP 不是由后端开发者来独⽴完成的。
    前端 —> HTML 静态⻚⾯ —> 后端 —> JSP
    这种开发⽅式效率极低,可以使⽤前后端分离的⽅式进⾏开发,就可以完美地解决这⼀问题

    前端只需要独⽴编写客户端代码,后端也只需要独⽴编写服务端代码提供数据接⼝即可
    前端通过 Ajax 请求来访问后端的数据接⼝,将 Model 展示到 View 中即可

    前后端开发者只需要提前约定好接⼝⽂档(URL、参数、数据类型…),然后分别独⽴开发即可,前端 可以造假数据进⾏测试,完全不需要依赖于后端,最后完成前后端集成即可,真正实现了前后端应⽤的 解耦合,极⼤地提升了开发效率。
    单体 —> 前端应⽤ + 后端应⽤

    前端应⽤:负责数据展示和⽤户交互
    后端应⽤:负责提供数据处理接⼝

    前端 HTML —> Ajax —> RESTful 后端数据接⼝
    传统的单体应⽤

    前后端分离的结构

    前后端分离就是将⼀个单体应⽤拆分成两个独⽴的应⽤,前端应⽤和后端应⽤以 JSON 格式进⾏数据交互。
    1.5 实现技术使⽤ Spring Boot 进⾏后端应⽤开发,使⽤ Vue 进⾏前端应⽤开发。
    Vue + Element UI,Vue 集成 Element UI,Element UI 后台管理系统主要的标签

    el-container:构建整个⻚⾯框架
    el-aside:构建左侧菜单
    el-menu:左侧菜单内容,常⽤属性

    :default-openeds:默认展开的菜单,通过菜单的 index 值来关联:default-active:默认选中的菜单,通过菜单的 index 值来关联
    el-submenu:可展开的菜单,常⽤属性

    index:菜单的下标,⽂本类型,不能是数值类型template:对应 el-submenu 的菜单名
    i:设置菜单图标,通过 class 属性实则

    el-icon-messae el-icon-menu el-icon-setting
    el-menu-item:菜单的⼦节点,不可再展开,常⽤属性

    index:菜单的下标,⽂本类型,不能是数值类型

    Element UI 表单数据校验
    定义 rules 对象,在 rules 对象中设置表单各个选项的校验规则。
    rules: { name: [ { required: true, message: 'error', trigger: 'blur' }, { min: 3, max: 5, message: '⻓度在 3 到 5 个字符', trigger: 'blur' } ]}

    required: true, 是否为必填项
    message: ‘error’, 提示信息
    trigger: ‘blur’,触发事件

    2.项目开发2.1 业务代码@RestController@RequestMapping("/book")@CrossOriginpublic class BookHandler { @Autowired private BookRepository bookRepository; @GetMapping("/findAll/{page}/{size}") public Page<Book> findAll(@PathVariable("page") Integer page, @PathVariable("size") Integer size){ Pageable pageable= PageRequest.of(page-1,size); return bookRepository.findAll(pageable); } @PostMapping("/save") public String save(@RequestBody Book book){ Book result = bookRepository.save(book); if(result != null){ return "success"; }else{ return "error"; } } @GetMapping("/findById/{id}") public Book findById(@PathVariable("id") Integer id){ return bookRepository.findById(id).get(); //返回的是optional,book上又包了一层,所以get才能取出来 } @PutMapping("/update") public String update(@RequestBody Book book){ Book result = bookRepository.save(book); if(result != null){ return "success"; }else{ return "error"; } } @DeleteMapping("/deleteById/{id}") public void deleteById(@PathVariable("id") Integer id){ bookRepository.deleteById(id); }}
    2.2 前端视图层<template> <el-form style="width: 60%" :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"> <el-form-item label="编号" > <el-input v-model="ruleForm.id" readonly></el-input> </el-form-item> <el-form-item label="图书名称" prop="name"> <el-input v-model="ruleForm.name"></el-input> </el-form-item> <el-form-item label="作者" prop="author"> <el-input v-model="ruleForm.author"></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="submitForm('ruleForm')">修改</el-button> <el-button @click="resetForm('ruleForm')">重置</el-button> </el-form-item> </el-form></template><script> export default { data() { return { ruleForm: { id:'', name: '', author: '', }, rules: { name: [ { required: true, message: '图书名不能为空哦', trigger: 'blur' }, ], author: [ { required: true, message: '作者不能为空哦', trigger: 'blur' }, ] } }; }, methods: { submitForm(formName) { const _this=this; this.$refs[formName].validate((valid) => { if (valid) { axios.put('http://localhost:8181/book/update',this.ruleForm).then((res=>{ if(res.data=="success"){ _this.$alert('《'+_this.ruleForm.name+'》修改成功', '恭喜你',{ confirmButtonText: '确定', callback: action => { _this.$router.push('/BookManager'); } }); } })); } else { return false; } }); }, resetForm(formName) { this.$refs[formName].resetFields(); }, }, created() { /*要拿参数的时候写route 跳转的时候写router*/ const _this=this; axios.get('http://localhost:8181/book/findById/' + this.$route.query.id).then((res) => { _this.ruleForm=res.data; }); } }</script>
    3.项目展示主页

    修改页面

    添加图书

    删除图书

    4.总结其实因为我们做的只是一个比较简单的,课设级别的MIS,所以我就没有做的更细致一点,其实完全可以再产生几个表,用来根据学生ID来找相对应需要的信息,但这里就不再赘述,有兴趣的自己尝试一下。
    0  留言 2021-09-16 16:24:19
  • 基于springboot+redis+mysql实现的在线考试系统管理系统

    1.项目简介1.1 背景分析目前,许多高校绝大多数课程还采用考教统一的模式来完成教学过程,这种传统的考试模式在教学到实施考试的过程带有很大的主观随意性和不规范性。另外随着各高校近年来学生规模的扩大,教学任务日益繁重,教师的工作量相应的不断增加。迫切需要计算机辅助教学系统来打破这种传统的教学模式,减轻教师的工作负担,提高教学质量。因此,本文研究设计了一个试题库管理系统,来解决和缓解高校课程教学中现存的问题,提高教学质量和考试效果,减轻教师工作压力。试题库管理系统可辅助教师对所教科目的各种试题的题型、难度等相关资料进行保存、查询等信息管理;并在需要对学生进行测验、评估的时候,从题库中抽取出相应要求的题目,组成一套试卷。
    本文首先简要介绍了开发试题库管理系统的可行性分析,系统的需求分析和总体设计,然后主要针对系统的设计、组成、用户界面设计、程序设计进行了详细分析,并对系统部分关键性代码进行了讲解,同时对一般系统软件设计的基本思想及工作流程给出了方法技巧。首先在短时间内建立系统应用原型,然后,对初始原型系统进行需求迭代,不断修正和改进,直到形成用户满意的可行系统。
    1.2 功能模块1.2.1 在线考试模块
    考试倒计时、考试安排表
    答题卡、作答区
    批改完试卷后查看成绩情况以及参考答案

    1.2.2 题库系统模块
    课程分类
    题目列表、题目难度
    题目描述、参考答案等

    1.2.3 讨论区模块
    发布帖子、回帖、评论
    浏览帖子
    帖子编辑、删除

    1.2.4 个人中心模块
    更新个人信息、上传头像等
    考试记录
    发帖记录

    1.2.5 后台管理模块
    用户信息及权限管理
    考试管理
    教学大纲管理
    题目管理
    课程管理
    班级管理
    问卷调查管理
    成绩管理
    帖子管理
    评论管理

    1.2.6 功能模块图
    1.3 用户需求要设计一个性能良好的管理系统,明确用户的应用环境对系统的要求是首要的和基本的。本系统从以下四个方面对用户需求进行了分析:

    用户的需求信息:出题老师可以看到题目所属的类型和题目所考察的内容以及试题的分值和难度等级。当然这个权限也给管理员和系主任
    用户的处理要求: 教师可以对试题库进行插入和删除操作,出题老师可以凭借自己自定义的选题要求在试题库中选择自己需求的试题
    对系统的适应性、通用性要求: 要求系统不仅能提供一门课程的试题库管理,还要综合多么学科进行管理,建立一个高效的试题库管理系统
    对系统的安全性要求:要求进入系统必须口令校验

    1.4 技术选型
    后台技术选型

    SpringBoot(Spring、SpringMVC)MyBatisThymeleaf
    前端技术选型

    BootstrapjQuery

    1.5 开发环境
    操作系统:Windows 10
    编程语言: Java 8
    开发工具: IDEA、Navicat、Git
    项目构建: Maven 3.3.9
    服务器:Tomcat 9.0
    数据库: MySQL、Redis

    1.6 部署
    用sql目录下的脚本文件初始化数据库并修改配置文件中密码
    **解压群文件的图片文件到本地文件夹,并修改Const中的文件路径
    **本地要安装redis,并启动redis服务,不用设置账号密码

    2.数据库设计2.1 表结构用户表

    班级表

    帖子表

    考试表

    成绩表

    博客文章表

    题目表

    调查问卷表

    评论表

    学科表

    课程管理表

    2.2 E-R图
    3.项目开发//获取所有题目@RequestMapping(value = "/api/questionList/{contestId}", method = RequestMethod.GET)@ResponseBodypublic AjaxResult getOtherQuestionList(HttpServletRequest request, @PathVariable int contestId) { AjaxResult ajaxResult = new AjaxResult(); Account currentAccount = (Account) request.getSession().getAttribute(Const.CURRENT_ACCOUNT); //TODO::处理 //currentAccount = accountService.getAccountByUsername("admin"); if (currentAccount == null || currentAccount.getLevel() < 1) { ajaxResult.setMessage("用户尚未登录"); } else { List<Question> questions = questionService.getOtherQuestionsByContestId(contestId); ajaxResult.setData(questions); } return ajaxResult;}//添加考试题目@RequestMapping(value = "/api/addContestQuestion", method = RequestMethod.POST)@ResponseBodypublic AjaxResult addContestQuestion(@RequestBody Question question) { boolean res = questionService.addContestQuestion(question); return new AjaxResult().setData(res);}//添加题目@RequestMapping(value = "/api/addQuestion", method = RequestMethod.POST)@ResponseBodypublic AjaxResult addQuestion(@RequestBody Question question) { int questionId = questionService.addQuestion(question); return new AjaxResult().setData(questionId);}//更新题目信息@RequestMapping(value = "/api/updateQuestion", method = RequestMethod.POST)@ResponseBodypublic AjaxResult updateQuestion(@RequestBody Question question) { boolean result = questionService.updateQuestion(question); return new AjaxResult().setData(result);}//删除题目信息@DeleteMapping("/api/deleteQuestion/{id}")public AjaxResult deleteContest(@PathVariable int id) { boolean result = questionService.deleteQuestion(id); return new AjaxResult().setData(result);}//删除题目信息@ResponseBody@RequestMapping(value = "/api/deleteContestQuestion", method = RequestMethod.POST)public AjaxResult deleteContestQuestion(@RequestBody Question question) { boolean result = questionService.deleteContestQuestion(question); return new AjaxResult().setData(result);}
    4.项目展示4.1 学生用户首页

    在线考试

    考试界面

    交卷页面

    讨论区

    4.2 助教题库中心

    个人中心

    部分权限

    帖子管理

    评论管理

    4.3 教师用户考试管理

    题目管理

    所负责课程管理

    所负责考试管理

    4.4 超级管理员所有考试管理

    所有课程管理

    成绩管理

    用户管理


    5.总结经过一周的设计和开发,试题库管理系统基本开发完毕。其功能基本符合学校管理者需求,能够完成各个专业各门学科的试题录入,根据要求自动成卷等多方面的功能。
    0  留言 2021-09-13 09:23:29
  • 基于springboot的购物商城管理系统

    1.项目简介1.1 用户简介用户主要分为管理员和用户端:

    管理员: 管理员可以对后台数据进行管理、拥有最高权限、具体权限有登录后进行首页轮播图的配置管理、商品的配置、新品家具商城的配置管理、、家具商城分类管理配置、家具商城详情商品管理、用户管理、订单管理以及、修改密码等操作
    客户端用户:用户输入家具商城网站系统地址、可以浏览家具商城信息、需要查看详情或其他购买加入购物车等操作需要用户进行登录、,没有账号的用户可以进行注册操作、输入相关注册信息完成注册后登录。登录完成后可以进行商品的购买、商品查询、加入购物车、修改收货地址等一系列操作

    1.2 技术栈主要技术实现:spring、 springboot、 mybatis 、 jquery 、 md5 、bootstarp.js tomcat、富文本编译器、拦截器等
    1.3 功能模块1.3.1 前端用户
    用户注册和登录登录功能

    用户的注册功能 : 访问网站的人根据网站的提示注册自己的账户用户的登录功能 : 用户可以输入用户名和密码进行登录操作,当没有该账户的时 候,提示错误,用户必须通过注册完成或者从数据库中获取才能进行会员权限级别的操 作。登录成功之后可以购买商品,查询订单的详细信息
    个人信息的管理

    用户信息的修改操作,其中包括会员名、密码、性别、联系方式 e-mail 和个人介 绍等用户信息的修改操作。但是会员邮箱是绑定账号的,会员邮箱不能进行更改操作订单管理操作:订单只能查询和删除操作,不能有修改操作,修改操作是属于管理员的权限用户退出操作:当点击用户退出时,就会退出当前用户的登录状态,恢复到游客状态
    商品的操作

    搜索商品操作: 当在 Search 栏输入想搜索的家居用品时, 会使用模糊查询, 搜索 出客户想到查询的家居用品商品列表展示商品详细信息展示购物车的管理操作显示商品信息:当我们一进入购物车页面,就会显示出商品的详细信息,以及购 物车界面的功能信息修改商品的数量:用户可以自己输入不同数量的商品,当商品的数量变动时,商 品的库存就会相应的减少,也会根据商品的数量得到购买这一种商品的金额小计删除购物车中的商品购物流程变动
    订单管理操作

    订单生成:进入结算中心,会提示用户已经登录成功并来到结算中心,然后在提 交订单的时候生成了一份订单,会显示在确认订单页面确认订单:当点击确认订单的时候会进入支付页面,那里会真正的付款操作订单查询:在我的订单页面会显示订单的详细信息,我们可以查询我们想要的订单信息订单管理:在我的订单页面会显示所有订单的信息,可以在那里删除订单,查询 订单等

    1.3.2 后台管理员系统的后台是专门为管理家居商城系统的人员设计的,功能如下:

    超级管理员:拥有管理该系统的最大权限,他有两个特有的功能

    数据字典:可以对后台的不同分类的分类列表具有增删改查的操作角色管理:将拥有不同权限的管理员分成不同的角色,每个不同角色有自己的权限,不能执行越权操作
    商品分类的管理

    添加编辑分类:点击添加按钮,会跳转到分类添加页面,需要编写分类名称,分类描述信息删除分类:当点击删除按钮时,会弹出一个提醒框,当点击确定,删除分类,点击取消,保持原来不变
    商品管理功能

    查询商品 : 查询所有商品列表, 还有通过商品的名称、 商品的类别和价格区间查询添加修改商品 : 点击添加商品会转到添加商品页面, 需要提供商品名称、 商品图片、商 5 6 品类别、商品价格、库存数量、商品描述等内容删除商品:删除商品

    2.数据库设计2.1 表结构用户表

    收货地址表

    购物车表

    分类表

    评论表

    商品表

    订单详情表

    产品信息表

    2.2 E-R图
    3.项目实现3.1 业务代码/** * 后台管理登录验证 */@PostMapping("login")@ResponseBodypublic Map<String,Object> login(User user, String verity, HttpSession session){ Map<String, Object> map = new HashMap<String, Object>(); String adminLogin = session.getAttribute("adminLogin")+""; if (!adminLogin.toUpperCase().equals(verity.toUpperCase())){ map.put("state", "error"); map.put("msg", "验证码输入错误,请重新输入"); return map; } return userAdminService.Login(user,session,verity);}@PostMapping("upload")@ResponseBodypublic String upload(MultipartFile file){ String filename = file.getOriginalFilename(); String name = filename.substring(filename.lastIndexOf(".") + 1, filename.length()); String s = UUID.randomUUID().toString(); File filepath = new File("D:\\work\\ideaprojects\\gitAdmin\\shop\\upload\\"+s+"."+name); try { file.transferTo(filepath); } catch (IOException e) { e.printStackTrace(); return null; } return "http://image.shop.com/"+s+"."+name;}@PostMapping("update")@ResponseBodypublic String update(User user){ return userAdminService.update(user);}@GetMapping("delete")@ResponseBodypublic String delete(Long id){ Integer delete = userAdminService.delete(id); if (delete>0){ return "ok"; } return "error";}@PostMapping("save")@ResponseBodypublic String save(User user){ Integer save = userAdminService.save(user); if (save>0){ return "ok"; } return "error";}
    public Map<String, Object> reg(User user) { //初始化返回参数 Map<String, Object> map = new HashMap<String, Object>(); //初始化查询参数 User us = new User(); //根据用户名查询该用户是否存在 us.setUsername(user.getUsername()); if (userDao.selectOne(us) != null) { map.put("state", "error"); map.put("msg", "该用户已存在,请重新注册"); return map; } //使用md5加密密码 user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes())); //添加默认值 user.setRole("普通用户"); user.setHeader_url("img/txs.jpg"); user.setCreated(new Date()); user.setUpdated(new Date()); userDao.insertSelective(user); map.put("state", "success"); return map;}public Map<String, Object> login(User user, HttpSession session) { //初始化返回参数 Map<String, Object> map = new HashMap<String, Object>(); user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes())); User selectOne = userDao.selectOne(user); if (selectOne==null) { map.put("state", "error"); map.put("msg", "用户名或者密码输入错误,请重新输入"); return map; } map.put("state", "success"); Cart cart = new Cart(); cart.setUid(selectOne.getId()); user.setCartList(cartService.queryByGidUid(null,selectOne.getId())); System.out.println(user.getCartList()); Address address = new Address(); address.setUserId(selectOne.getId()); selectOne.setAddress(addressDao.selectOne(address)); session.setAttribute("portalUser",selectOne); return map;}public User update(User user) { userDao.updateByPrimaryKeySelective(user); return userDao.selectByPrimaryKey(user.getId());}public User upload(MultipartFile file,Long id) { String filename = file.getOriginalFilename(); try { String name = filename.substring(filename.lastIndexOf(".") + 1, filename.length()); String s = UUID.randomUUID().toString(); file.transferTo(new File("D:\\work\\ideaprojects\\gitAdmin\\shop\\upload\\"+s+"."+name)); User user = new User(); user.setHeader_url("http://image.shop.com/"+s+"."+name); user.setId(id); userDao.updateByPrimaryKeySelective(user); } catch (IOException e) { e.printStackTrace(); } return userDao.selectByPrimaryKey(id);}public void changePassword(User user) { user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes())); userDao.updateByPrimaryKeySelective(user);}public User queryById(Long id) { User user = userDao.selectByPrimaryKey(id); user.setCartList(cartService.queryByGidUid(null,id)); Address address = new Address(); address.setUserId(user.getId()); user.setAddress(addressDao.selectOne(address)); return user;}
    3.2 前端视图代码编写<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <meta name="renderer" content="webkit"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <title>商城后台管理系统</title> <link rel="stylesheet" type="text/css" href="../admin/layui/css/layui.css"/> <link rel="stylesheet" type="text/css" href="../admin/css/admin.css"/> </head> <body> <div class="main-layout" id='main-layout'> <!--侧边栏--> <div class="main-layout-side"> <div class="m-logo"> </div> <ul class="layui-nav layui-nav-tree" lay-filter="leftNav"> <li class="layui-nav-item"> <a href="javascript:;" data-url="../admin/user" data-id='1' data-text="用户管理"><i class="iconfont"></i>用户管理</a> </li> <li class="layui-nav-item"> <a href="javascript:;" data-url="../admin/comment" data-id='3' data-text="评价管理"><i class="iconfont"></i>评价管理</a> </li> <li class="layui-nav-item layui-nav-itemed"> <a href="javascript:;"><i class="iconfont"></i>商品管理</a> <dl class="layui-nav-child"> <dd><a href="javascript:;" data-url="../admin/goods" data-id='4' data-text="商品管理"><span class="l-line"></span>商品管理</a></dd> <dd><a href="javascript:;" data-url="../admin/category" data-id='6' data-text="商品分类管理"><span class="l-line"></span>商品分类管理</a></dd> </dl> </li> <li class="layui-nav-item"> <a href="javascript:;" data-url="../admin/admin-info" data-id='8' class="page" data-text="个人信息"><i class="iconfont"></i>个人信息</a> </li> </ul> </div> <!--右侧内容--> <div class="main-layout-container"> <!--头部--> <div class="main-layout-header"> <div class="menu-btn" id="hideBtn"> <a href="javascript:;"> <span class="iconfont"></span> </a> </div> <ul class="layui-nav" lay-filter="rightNav"> <li class="layui-nav-item"> <a href="javascript:;" class="page" data-url="../admin/admin-info" data-id='5' data-text="个人信息">超级管理员</a> </li> <li class="layui-nav-item"><a href="../admin/login">退出</a></li> </ul> </div> <!--主体内容--> <div class="main-layout-body"> <!--tab 切换--> <div class="layui-tab layui-tab-brief main-layout-tab" lay-filter="tab" lay-allowClose="true"> <ul class="layui-tab-title"> <li class="layui-this welcome">后台主页</li> </ul> <div class="layui-tab-content"> <div class="layui-tab-item layui-show" style="background: #f5f5f5;"> <!--1--> <iframe src="../admin/welcome" width="100%" height="100%" name="iframe" scrolling="auto" class="iframe" framborder="0"></iframe> <!--1end--> </div> </div> </div> </div> </div> <!--遮罩--> <div class="main-mask"> </div> </div> <script type="text/javascript"> var scope={ link:'../admin/welcome' } </script> <script src="../admin/layui/layui.js" type="text/javascript" charset="utf-8"></script> <script src="../admin/js/common.js" type="text/javascript" charset="utf-8"></script> <script src="../admin/js/main.js" ></script> </body></html>
    4.项目展示4.1 前端部分主页


    登录

    注册

    4.2 后台管理登录

    主页

    用户管理

    评论管理

    商品管理

    商品分类管理

    个人信息管理

    5.总结前端部分要集中精力做前端页面的效果,bootstrap模板支撑,js,css,html,jq的代码逻辑通过ajax进行接口的请求调用,达到获取服务器数据的目的。
    后端部分要也是尽其所能的做好自己的事情,分层架构,模型的选取,接口、数据库设计,性能研究,不需要像jsp那样,还需要去操作前端的代码逻辑,填充数据。
    0  留言 2021-09-13 08:14:23
  • 基于Springboot+RabbitMQ+Redis实现的高校社团管理系统

    1.项目简介1.1 背景当前,大多数高校的社团信息管理都是采用纸质档案的方式来管理的,这样不仅不能长期的保存信息,而且在数据的查找上带来很大的不方便。在目前的网络技术和计算机技术的普及和信息管理的迅速发展,使用计算机,但总的趋势来实现。校园社区管理也可以支持用料计算机信息管理等,利用网络实现信息共享。这样不仅符合现代的管理要求,而且有助于将信息管理推向科学化、规范化。同时,用计算机去管理信息拥有各种优势,比如稳定性高、使用年限长、检索迅速、保密性好、存储量大、开销低等。这些优点能够减少相关人员工作量,极大地提高社团信息管理的效率。社团管理系统是基于Java作为开发语言,使用MySQL数据库作为后端数据存储,使用Idea作为研发开发的工具,信息化管理已经在信息社会为目标来实现的。本文分析了现有的大学社区管理为出发点的现状,已经研究制定方案,详细的社区管理体制分析和功能分析,总结了系统,数据库设计和展示的最终控制系统的结果数据结构的设计框架的功能需要的可行性社区项目,介绍了该系统用实验来验证结果表明,所有有关的各种功能ESS发展,以及经验和发展不足。
    1.2 项目描述本系统基于B/S的结构进行开发,使用java编程,对三类不同角色的用户进行登陆控制,主要按照校园社团运行的规则分配权限和模块,使社团管理从纸质版变为无纸化,方便社团的管理和运行。前端页面主要使用Layui框架,主要使用table组件。首页显示每个社团的信息和社团活动,数据库设计使用PowerDesigner软件,采用中间表实现一对多、多对多的表结构关系。首页使用<c:forEach>标签循环遍历输出不同类型的社团并显示社团信息。登陆是根据从数据库找到的用户类型的不同,进入到不同的个人主页。进入主页可以对不同模块的表进行增删改查,审核表除外。SQL语句的XML文件要配置映射关系,使数据封装成功。在开发过程中,主要遇到的问题有首页显示社团信息时由于社团信息的介绍长度不同,导致页面不美观,后来在SQL语句中加入了Length()函数对社团信息的长度进行排序之后,再显示到前台页面。此项目更一步加深了我对三层架构模式的理解和Spring MVC、MyBatis、Layui框架的使用。
    1.3 开发环境及技术栈
    开发技术:html、Springboot、Layui、Spring、Spring MVC、MyBatis、jQuery、Redis、RabbitMQ
    开发平台:Linux、JDK8、MySQL
    相关工具:IDEA、Tomcat、Navicat、Maven、PowerDesigner、Visio、UML

    在设计中,采用MVC(Model-View-Controller)模式,将程序的逻辑和页面分离,维护起来更加方便。数据库设计遵循数据库设计三范式。使用Layer和jQuery实现对页面的美化和后台的交互。
    1.4 功能
    管理员

    社团管理日记管理商城管理个人资料管理用户管理新闻管理
    普通用户

    注册登录加入社团浏览商城编写日记个人中心

    2.数据库设计2.1 表结构浏览次数表

    用户表

    菜单表

    日记表

    商品信息表

    主题表

    2.2 E-R图
    3.业务代码@RequestMapping("/bolgs")public String tomybolgs(Model model, HttpSession session){ //查询出来跳转到我的日志页面 IUser user = (IUser) session.getAttribute("user"); //通过user_id查询出该角色的所有日志信息 List<Log> logs = logService.getLogs(user.getId()); model.addAttribute("logs",logs); return "mybolgs";}@RequestMapping("/logedite")public String edite(@Param("id")String id,Model model){ //编辑数据,查询出数据后显示到edito中 Log log = logService.getLogById(id); model.addAttribute("log",log); return "editbolg";}@RequestMapping("/logdelete")public String delete(@Param("id") String id, Model model){ System.out.println("来到了delect中的数据源"); logService.deleteById(id); return "mybolgs";}@RequestMapping("/logcheck")public String check(@Param("id")String id,Model model){ Log log = logService.getLogById(id); model.addAttribute("log",log); return "bolg";}//图片上传@RequestMapping("/log/upload")@ResponseBodypublic ImgInfo setImgUrl(MultipartFile file, HttpServletResponse response, HttpServletRequest request) throws Exception { OSSClientUtil ossClientUtil = new OSSClientUtil(); String s = ossClientUtil.uploadImg2Oss(file); String url = ossClientUtil.getImgUrl(s); String value =url; String[] values = { value }; ImgInfo imgInfo = new ImgInfo(); imgInfo.setError(0); imgInfo.setUrl(values); return imgInfo;}@ResponseBody@PostMapping("/addlog")public String addlog(@Param("ht")String ht ,@Param("themes") String theme,HttpSession session) throws ParseException { System.out.println(ht+"====="+theme); //获取user_id IUser user = (IUser) session.getAttribute("user"); String id = user.getId(); Log log = new Log(); //获取当前系统的日期 Date date = new Date(System.currentTimeMillis()); String s = DateUtil.date2String(date); log.setDatee(s); log.setTheme(theme); log.setContent(ht); log.setUser_id(id); log.setEye(0); log.setUsername(user.getUsername()); log.setId(UUIDUtils.getUUID()); //查询出来把消息,保存到数据库中去 logService.insertLog(log); return "mybolgs";}
    4.项目展示登录

    首页

    个人日记

    个人信息

    加入社团

    编写日记

    商城

    5.总结
    经过近期对 java 相关知识面向对象程序设计、Java Web等的掌握和学习,让我更加了解到 java 学习的重要性。在开发这个社团系统,我完成多个实验以及测试,在这个阶段的学习开发中,我从认识到熟悉,而后到能够自主运用。通过对Springboot和消息中间件Rabbit MQ知识以及数据库的设计相关的了解,我发现它确实有很多方便之处,它集抽象性、封装性、继承性和多态性于一体,实现了代码重用和代码扩充,提高了软件开发的效率。对于我们这个专业来说学好 java 语言是很重要的,所以在开发这个项目的过程中我都尽力理解 java 编程思想、掌握基本技巧,尽量学到最多的知识。 我学习程序设计的基本目的就是培养描述实际问题的程序化解决方案的关键技能,总体来说 java 面向对象程序设计是一门实践性比较强的语言。
    0  留言 2021-09-11 07:20:40
  • 基于SSM和Layui实现的图书管理系统

    1. 项目介绍通过一段时间对SSM整合的学习,对基本理论以及主要知识点的掌握,实现简易图书管理系统,当然肯定有很多可以改进的地方。之前没有记录SSM整合的过程,这次刚好项目有更深刻的理解。以前解决问题的过程和方法并没有及时记录,以后在自己的小项目中遇到我再整理分享一下。这次,先说说三大框架整合过程。个人认为使用框架并不是很难,关键要理解其思想,这对于我们提高编程水平很有帮助。不过,如果用都不会,谈思想就变成纸上谈兵了!!!先技术,再思想。实践出真知。
    项目中相关的配置文件,大家可以拿来直接copy ,只需要改改里面的包名以及Mapper.xml配置即可使用。
    分为管理员、用户和图书模块。其中管理员实现了登录,对读者与图书的增删改查,还有管理读者的图书借阅、续借、归还、预约和逾期处理。
    该项目已实现功能:

    管理员的登录与退出,登录错误提示
    图书的新增,修改,下架,彻底删除,重新上架,分页显示,按照图书标题与作者名字模糊查询
    还有其它未完成的功能可自由发挥,包括登录后的欢迎页面可自由发挥
    该系统执行过程无任何报错,如果出现错误请仔细检查配置

    软件架构

    MyEclipse
    SSM框架
    JSP
    MySQL8
    Tomcat8.5
    Maven

    使用说明

    借阅:同一本书只可借阅一本,每次可借30天
    续借:同一本书只可续借一次,每次续借15天
    归还:在归还日期内方可归还图书
    预约:当图书余量为0时,可预约该图书
    逾期处理:需缴费,分为缴费并还书和缴费未还书
    上架图书:需要输入图书基本信息和上架数量

    2.数据库设计2.1 表结构管理员表

    图书表

    借阅记录表

    分类表

    2.2 E-R图
    3.搭建数据库创建一个存放书籍数据的数据库(library_oa),并在该数据库中建立一个名为ms_book的表,代码如下:
    DROP TABLE IF EXISTS `ms_book`;CREATE TABLE `ms_book` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(255) DEFAULT NULL COMMENT '书名', `ISBN` varchar(255) DEFAULT NULL COMMENT '统一使用07年新颁布的13位数字', `author` varchar(255) DEFAULT NULL COMMENT '作者', `introduction` varchar(255) DEFAULT NULL COMMENT '简介', `price` varchar(255) DEFAULT NULL COMMENT '价格', `publish_time` varchar(255) DEFAULT NULL COMMENT '出版时间', `category_id` int(10) DEFAULT NULL COMMENT '类别', `image` varchar(255) DEFAULT NULL COMMENT '图片url', `create_time` date DEFAULT NULL COMMENT '上架时间', `create_admin` varchar(255) DEFAULT NULL COMMENT '上架管理员', `update_pre_admin` varchar(255) DEFAULT NULL COMMENT '上一次修改信息的管理员', `del_flg` int(1) DEFAULT NULL, `sum` int(11) NOT NULL, `remainder` int(11) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;-- ------------------------------ Records of `ms_book`-- ----------------------------BEGIN;INSERT INTO `ms_book` VALUES ('1', '活着', '9787506365437', '余华', '《活着》是作家余华的代表作之一,讲述了在大时代背景下,随着内战、三反五反,大跃进,文化大革命等社会变革,徐福贵的人生和家庭不断经受着苦难,到了最后所有亲人都先后离他而去,仅剩下年老的他和一头老牛相依为命。', '25.30', '1923年6月', '1', '', '2019-04-13', 'Bob', '大天狗', '1', '10', '7'), ('3', '2', '2', '2', '2', '2', '2020-05-21', '1', '38a77897-124f-403d-96da-942192b3fa15', '2020-05-21', 'Bob', 'Bob', '1', '2', '0'), ('4', '3', '3', '3', '3', '3', '2020-05-21', '2', '38be617c-5aa3-41b3-bf7e-f343d4a17cf7', '2020-05-21', 'Bob', 'Bob', '1', '3', '1'), ('5', '4', '4', '4', '4', '4', '2020-05-22', '3', 'f4bc6a21-64fb-4ce9-a9ec-fec193362c3d', '2020-05-21', 'Bob', 'Bob', '1', '4', '2'), ('6', '5', '5', '5', '5', '5', '2020-05-21', '4', '3be0532c-48a2-4ea8-b6e0-b1053f18e871', '2020-05-21', 'Bob', 'Bob', '1', '5', '4'), ('7', '6', '6', '6', '6', '6', '2020-05-21', '5', '46ed11c5-5819-4d23-b58a-0a96084e3a12', '2020-05-21', 'Bob', 'Bob', '1', '6', '5'), ('8', '7', '7', '7', '7', '7', '2020-05-21', '6', '63dcaf76-0f07-476b-a529-e0680b15e832', '2020-05-21', 'Bob', 'Bob', '1', '7', '7'), ('9', '8', '8', '8', '8', '8', '2020-05-28', '7', '7ef89434-7c77-47d8-8a2a-2f72866f0ddc', '2020-05-21', 'Bob', 'Bob', '1', '8', '8'), ('10', '9', '9', '9', '9', '9', '2020-05-21', '8', '425b7fd7-c1d3-4bc8-9390-c8d3d4baef7a', '2020-05-21', 'Bob', 'Bob', '1', '9', '9'), ('11', '10', '10', '10', '10', '10', '', '9', 'f4d173fd-b194-4a07-8663-0b47b7e8ab6f', '2020-05-21', 'Bob', 'Bob', '1', '10', '10'), ('12', '11', '11', '11', '11', '11', '2020-05-22', '8', '9500c8d2-ce65-4970-9b3d-3220fe9ed159', '2020-05-21', 'Bob', 'Bob', '1', '11', '11');COMMIT;
    写好数据库的配置文件database.properties,该文件可以放在resources目录下,代码如下:
    url=jdbc:mysql://localhost:3306/library_oa?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghaidriver=com.mysql.cj.jdbc.Driverusername=rootpassword=123456initialSize=5maxActive=50
    在Maven中导入数据库连接所需要的驱动包(mysql-connector),代码如下:
    <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version></dependency>
    4.项目展示4.1 普通用户登录

    首页

    图书列表

    查询

    借阅


    续借

    4.2 管理员图书列表

    上架书籍

    管理借阅记录

    读者管理

    查看逾期列表

    5.总结尽管现在的Java Web项目的开发多用Spring Boot进行搭建,但是使用相对原生的SSM(Spring + Spring MVC + Mybatis)进行开发,不仅能让我们对于Web项目的搭建流程更加熟悉,还会对我们在日后的学习和工作中大有裨益。
    0  留言 2021-09-11 07:16:09
  • 基于Springboot和Layui实现的宿舍管理系统

    1.项目介绍项目主要使用axios进行前后端数据的交互,之所以采用axios不使用ajax的原因是因为看中了axios的拦截器,可以更好的帮我们完成项目。
    1.1 摘要现如今高校大学生越来越多,寝室压力巨大,学生不好管理。学生宿舍管理系统对于一个学校来说是必不可少的组成部分。目前好多学校还停留在宿舍管理人员手工记录数据的最初阶段,手工记录对于规模小的学校来说还勉强可以接受,但对于学生信息量比较庞大,需要记录存档的数据比较多的高校来说,人工记录是相当麻烦的。而且当查找某条记录时,由于数据量庞大,还只能靠人工去一条条的查找,这样不但麻烦还浪费了许多时间,效率也比较低。本文构建了一个基于B/S模式的学生宿舍管理系统,为学生、学校和宿管阿姨搭建了一个灵活自由并且安全可靠的管理平台。本文着重论述了系统的模块设计、数据流程和功能实现。本系统一共设计3种用户的登录了其功能包括寝室宿舍管理员管理、学生管理、宿舍楼管理、缺勤记录、账户密码的修改等功能。包括如何运用JAVA、JavaScript、html等关键技术建立网上购物系统,并在web服务器上配置SSL以保证敏感信息的安全传输。
    关键词:学生宿舍;数据库;学校管理;
    当今社会是飞速进步的世界,原始的记录方式已经被社会所淘汰了,计算机化管理正是适应时代的产物。信息世界永远不会是一个平静的世界,当一种技术不能满足需求时,就会有新的技术诞生并取代旧技术。21世纪的今天,信息社会占着主流地位,计算机在各行各业中的运用已经得到普及,自动化、信息化的管理越来越广泛应用于各个领域。我们针对如此,设计了一套学生宿舍管理系统。学生宿舍管理系统采用的是计算机化管理,系统做的尽量人性化,使用者会感到操作非常方便,管理人员需要做的就是将数据输入到系统的数据库中去。由于数据库存储容量相当大,而且比较稳定,适合较长时间的保存,也不容易丢失。这无疑是为信息存储量比较大的学校提供了一个方便、快捷的操作方式。本系统具有运行速度快、安全性高、稳定性好的优点,并且具备完善的报表生成、修改功能,能够快速的查询学校所需的住宿信息。
    1.2 需求分析1.2.1 系统概述软件旨在宿舍管理全部电脑化。它主要可以更快地了解到每个学生的住宿情况,使宿舍的管理效率更高,做的更好!宿舍管理系统是一个现代化软件,他通过集中式的信息数据库将各种档案管理功能结合起来,达到共享数据,降低成本,提高效率,改进服务等目的。
    系统运行环境:

    JDK1.8——JAVA的运行环境
    Tomcat8.5——web服务器
    Windows10/7——操作系统
    MySQL Server 8.0——数据库

    1.2.2 功能需求描述在整体设计中,我们将宿舍管理系统分为四个页面:登录页面、系统管理员页面,宿舍管理员页面、学生页面下面将具体进行介绍每个页面的功能。

    登录页面:登录页面的功能包括:用户登录、选择用户类型、记住用户三个功能
    系统管理员页面:系统管理员页面功能包括:宿舍管理员管理、学生管理、宿舍楼管理、缺勤记录、账户密码的修改、退出系统六个功能
    宿舍管理员页面:宿舍管理员页面功能包括: 学生查看、缺勤记录、修改密码、退出系统四个功能
    学生页面:学生页面功能包括:缺勤记录、修改密码、退出系统三个功能

    1.2.3 运行模块组合具体软件的运行模块组合为程序多窗口的运行环境,各个模块在软件运行过程中能较好的交换信息,处理数据,例如:学生信息查询子模块。
    学生信息查询子模块运行时,通过用户界面与sql2000学生信息数据库链接,搜索与用户输入的学生信息管理子模块。
    信息更新(添加、删除、修改)子模块运行时,学生信息管理员通过管理界面接口与数据链接,进行对学生信息的更新,和相关数据的操作。
    1.2.4 对功能的规定
    主界面登录:是本系统的主界面,在该界面中,用户可以选择所要进行的操作如:数据录入,数据查询,数据统计等操作
    系统后台:主要是数据库的逻辑关系的建立,和重要信息的存储管理,通过主界面对后台数据信息进行管理,比如:信息的录入、修改、删除等操作

    1.2.5 数据需求分析数据库需求分析调查的重点是“数据”和“处理”,通过调查、收集和分析,获得用户对数据库的需求。

    信息需求:指用户需要从数据库中获得信息的内容与性质,即在数据库中需要存储哪些数据
    处理要求:指用户需要完成什么处理能力。明确用户对数据有什么样的处理要求从而明确数据之间的关系

    本课程的功能集中表现为数据的查询,更新和维护,因此需求集中表现为对“数据”的需求。根据登陆身份不同显示不同的功能项,以及所能进行的操作。
    概念结构设计是将缝隙得到的用户需求抽象为概念模型的过程,他是整个数据库设计的关键。
    1.2.6 性能需求分析学生宿舍管理系统中管理权限上应当进行严格控制,具体思想如下:

    要想对该学生宿舍管理系统进行操作就应当具有某些操作权限。没有权限的用户将不能通过任何渠道来登录该系统,查看该系统的任何信息和数据,以确保系统的严密性和安全性
    在上述要求基础上可以为该系统设定多种登录方式,程序开始运行所有功能将是不可使用的,只有系统管理员登录和普通用户登录两个窗口可以使用,没有系统管理员或者普通用户的用户名和密码任何人都不能登录该系统
    在具体实现时还应为系统管理员和普通用户设定不同的权限,系统管理员应当可以使用系统的所有模块,普通用户对于用户管理模块是无权使用的

    本系统可以实现许多性能特性,如:实用性、灵活性、可扩展性、易维护性、可靠性等等。 实用性是衡量一个应用系统好坏的重要指标。是否与业务紧密结合,是否具有严格的业务针对性,是系统成败的关键。本系统提供了灵活的查询模块可查询同学的联系方式、学生违纪、留言板等信息,灵活组合条件,进行组合查询,达到提高查询效率、界面直观的效果。随着系统应用的普及和推广,系统功能的扩展将是不可避免的,因此,提高系统的可扩展性、可维护性是提高整个系统性能的必然要求。 本系统采用模块化的设计思想,在结构上具有良好的可伸缩性,使用者可根据实际业务需要扩展模块。本系统采用多层架构设计,使系统结构更清楚,分工更明确,有利于后期的维护。
    1.3 程序设计说明在整体设计中,我们将宿舍管理系统在使用者登陆时分为系统设置、学生住宿管理信息、卫生评比等七个模块。接下来,在各自的模块中分别实现各自的功能。在每个模块下有分有不同的功能的子模块。每个模块将实现不同的功能。下面将具体进行介绍。
    1.3.1 登录模块
    功能简介:在系统的登录界面实现系统管理人员或学生的一般用户使用正确的该系统的用户名和密码登录到不同模式中,以及用户在不能正常登陆时安全退出系统
    输入项:根据需求分析报告中所述,输入项为用户信息(学生信息或者理员信息)。 用户信息:用户ID,用户密码,用户类型(普通用户,管理员)
    输出项:根据概要设计报告中模块设计的思路,该登录模块输出项为:控制代码,是被调模块的名字
    算法:该登录模块中应用选择算法,根据用户的要求选择不同的模式
    接口:本模块为最初的主模块,没有上层模块,根据用户要求调用子模块;在模块的检查用户的合法性时需要调用系统的查询模块,传递参数是用户信息。该模块不直接操作数据库文件
    存储分配:根据学生宿舍管理系统需要分析说明以及概要设计的设计思路,系统的登录模块存储在所有数据的最前面,加快系统的进入速度

    1.3.2 管理模块
    功能简介:该管理模块的功能可以概述为:承接的作用。调用管理员要求的操作模式,查询或者登记
    输入项:管理员根据系统界面的提示,选择操作类型,该类型对应的是模块的名字
    输出项:根据概要设计报告中模块设计的思路,该管理模块输出项为:控制代码,是被调模块的名字
    算法:该管理模块中应用选择算法,根据管理员的选择要求选择不同的操作模式
    接口:本模块为只调用下层信息查询模块或者登记模块,传的数据是全局唯一的模块的名字
    存储分配:该管理模块按照顺序模块放在登录模块之后即可实现系统的功能且不影响运行速度

    1.3.3 管理员信息查询模块
    功能简介:该模块功能在管理员模式中实现,具体实现学生夜归信息,住宿信息,快件信息和已修信息的查询功能
    输入项:根据需求分析报告中所述,输入的查询条件可以分为按宿舍号,按物品号查询报修信息;按学号,宿舍号查询学生的夜归信息;按学号,姓名,专业查询学生的住宿情况;按学号,姓名,专业查询学生的快件信息
    输出项:该查询模块的输出数据为固定结构的数据项,将管理员填写的查询条件封装在固定的数据类型中传递给被调用的数据库查询模块。结构基本就是数据的存储结构,具体可见需求分析报告
    算法:该登录模块中采用的算法基本同等级模块相同,为满足管理员的要求可能将管理员的查询条件进行相应的数据格式装换,确保系统的稳定,安全,可靠
    接口:信息查询模块是中间模块隶属与上层模块,下层调用有关数据库查询操作的模块,调用时将封装好的数据结构传递给下层模块
    存储分配:同样考虑到系统管理员是该系统的常用的操作者,并且查询操作是管理员最常用的操作,为了便于管理员快速的进行管理操作,将该模块按照顺序存储在管理模块之后

    1.3.4 管理员信息登记模块
    功能简介:该模块功能是管理员模式的重要功能,具体实现对学生夜归信息,住宿信息,快件信息和报修信息的登记(包括新增,删除,修改)功能,以便管理的顺利进行
    输入项:根据需求分析报告中所述,输入项为可以有4种

    住宿学生信息:学号,姓名,性别,院系,宿舍号,入住时间夜归信息:学号,宿舍号,晚归时间,晚归原因离校信息:学号,宿舍号,离校时间,返回时间已修信息:宿舍号,物品号,提交日期,报修原因
    输出项:该登记模块的输出数据为固定结构的数据项,将管理员填写的信息封装在固定的数据类型中传递给被调用模块。三种结构基本就是数据的存储结构,具体可见与需求分析报告
    算法:该登录模块中应用选择算法,可能应按用户的输入要求进行相应的数据格式装换,确保系统的稳定,安全
    接口:信息登记模块是中间模块隶属与上层的登录模块,下层调用有关数据库的对数据操作的模块,调用时将封装好的数据结构传递给下层模块
    存储分配:考虑到系统管理员是该系统的最常用的操作者,便于管理员快速的进行管理操作,将该模块按照顺序存储在查询模块之后

    1.3.5 学生管理模块
    功能简介:学生管理模块用以实现学生的报修登记,快件收取,信息登记和信息查询的全部功能,并且实现对下层数据库操作模块的调用
    输入项:该模块的输入项包括财务的报修信息,快件收取信息,详细信息参照需求说明书
    输出项:该模块的输出数据同样为固定结构的数据项,将管理员填写的信息封装在固定的数据类型中传递给被调用的下层模块
    算法:模块的实现算法简单没有具体要求,可以是顺序,也可以是选择,保证没有逻辑错误,具体逻辑流程见下图
    接口:该学生管理模块是中间模块隶属与上层的登录模块,下层调用有关数据库的对数据修改和查询的模块,调用时将封装好的数据结构传递给下层模块

    1.3.6 数据库查询模块
    功能简介:该数据库查询模块顾名思义就可知道是基于数据库操作的模块,用于实现上层模块调用进行数据库的查询操作
    输入项:该数据库查询模块是基于数据库操作的模块。输入数据为上层模块传递的固定结构的数据类型,包含住宿信息,报修信息,快件信息和夜归信息等
    输出项:输出项和输出项相同,为上层模块传递的固定结构的数据类型,包含住宿信息,报修信息,快件信息和夜归信息等
    算法:本模块算法简单,符合数据库要求的合理即可
    接口:该模块是基于数据库操作的模块,要和数据库进行通信,这里采用SQL语句

    1.3.7 数据库修改模块
    功能简介:该数据库查询模块顾名思义就可知道是基于数据库操作的模块,用于实现上层模块调用进行数据库的修改操作
    输入项:该数据库修改模块是基于数据库操作的模块。输入数据为上层模块传递的固定结构的数据类型,包含住宿信息,报修信息,快件信息和夜归信息等
    输出项:输出项和输出项相同,为上层模块传递的固定结构的修改数据类型,包含住宿信息,报修信息,快件信息和夜归信息等
    接口:该模块是基于数据库操作的模块,要和数据库进行通信,这里采用SQL语句

    1.4 出错处理设计1.4.1 出错信息在用户使用错误的数据或访问没有权限的数据后,系统给出提示:”对不起,你非法使用数据,没有权限!“而且用户的密码管理可以允许用户修改自己的密码,不允许用户的匿名登录。用户输入的信息是非中文字符,系统提示:您所输入的信息是非中文字符。 用户输入的信息是中文字符,但与本系统已收录的学生信息不匹配,系统提示:您所输入的信息不存在,请仔细核对您输入的信息是否在本系统收录的学生信息范围之内,重新输入,学生管理员输入的不符合数据的类型,系统提示:输入格式错误请重新输入。
    1.4.2 补救措施由于数据在数据库中已经有备份,故在系统出错后可以依靠数据库的恢复功能,并且依靠日志文件使系统再启动,就算系统崩溃用户数据也不会丢失或遭到破环,但有可能占用更多的数据存储空间,权衡措施由用户来决定。 系统软件出错很容易在出错日志里看到,我们对可能发生的错误会有一个错误编号以及相应的处理方式,以手册的方式提供。用户可以根据系统的提示信息进行相应的排错处理,建立系统运行日志,用于记录系统在运行过程中出现的可以预知的或无法判断的系统错误信息。硬件的出错处理信息需要检查网络环境。
    2.数据库设计2.1 表结构浏览表

    用户表

    菜单表

    学生表

    选宿舍表

    床位表

    学院班级表

    入住记录表

    待办事项表

    通知表

    宿舍表

    2.2 E-R图
    3.项目开发权限菜单
    @GetMapping("/query")public Result query(HttpServletRequest request){ List<Menu> menus = new ArrayList<>(); if(request.getAttribute("user") != null){ User user = (User) request.getAttribute("user"); menus = menuService.query(user.getId()); }else if(request.getAttribute("student") != null){ menus = menuService.queryByType(); } List<Menu> menuList1 = new ArrayList<>(); //找出一级菜单 for (Menu menu : menus) { if(menu.getParentId() == 0){ menuList1.add(menu); } } //嵌套循环找出关联设置child属性 for (Menu parent : menuList1) { List<Menu> child = new ArrayList<>(); for (Menu entity : menus) { if(parent.getId() == entity.getParentId()){ child.add(entity); } } parent.setChild(child); } return Result.ok(menuList1);}@GetMapping("/tree")public Result tree(Integer checked,HttpServletRequest request){ //check查询的时候是否选中状态 List<Integer> checkedMenuId = new ArrayList<>(); if(checked != null){ User user = (User) request.getAttribute("user"); //查询出来自己已经设置过得menuId checkedMenuId = menuService.queryCheckMenuId(checked); } List<Menu> list = menuService.list(); List<Map<String,Object>> menus = new ArrayList<>(); for (Menu menu : list) { if(menu.getParentId()==0){ Map<String,Object> map = new HashMap<>(); map.put("id",menu.getId()); map.put("name",menu.getTitle()); map.put("isParent",true); map.put("open",true); if(checked != null){ map.put("checked",checkedMenuId.contains(menu.getId())); } List<Map<String,Object>> child = new ArrayList<>(); for (Menu menu1 : list) { if(menu1.getParentId()!=0 && menu.getId() == menu1.getParentId()){ Map<String,Object> map2 = new HashMap<>(); map2.put("id",menu1.getId()); map2.put("name",menu1.getTitle()); map2.put("isParent",false); if(checked != null){ map2.put("checked",checkedMenuId.contains(menu1.getId())); } child.add(map2); } } map.put("children",child); menus.add(map); } } return Result.ok(menus);}
    登陆实现
    @PostMapping("/login")public Result login(@RequestBody User user){ if(user.getType() == 2){ //学生登录的 Student entity = studentService.login(user.getUserName(),user.getPassword()); System.out.println(entity); if(entity != null){ String token = JWTUtil.signForStudent(entity); Map map = new HashMap(); map.put(JWTUtil.token,token); map.put("student",entity); return Result.ok("登陆成功",map); }else{ return Result.fail("用户名或密码错误"); } }else{//管理员与宿管员登录 User entity = userService.login(user.getUserName(),user.getPassword()); if(entity != null){ String token = JWTUtil.sign(entity); Map map = new HashMap(); map.put(JWTUtil.token,token); map.put("user",entity); return Result.ok("登陆成功",map); }else{ return Result.fail("用户名或密码错误"); } }
    4.项目截图登录

    首页

    宿舍管理

    5.结论本系统使用了html,Java为开发语言,以Microsoft SQL数据库产品作为后台数据库,构建了一个灵活安全的学生宿舍管理系统。从系统的初步设计到最后系统的实现是经历了整体设计,逐步实现的过程。本文作为对系统的论述,重点介绍了系统开发环境、开发工具、开发语言等关键技术,分析了系统的数据库设计、系统流程设计、功能模块的详细设计、实现代码的分析和运行结果。论述了系统从设计到实现的一个完整的过程。系统采用了流行的B/S模式,实现了学生宿舍管理的功能,整个系统简洁易懂,层次分明,安全适用。由于篇幅有限,未能将所有模块的实现一一列出,只挑选了重要的部分加以说明。
    1  留言 2021-09-09 11:50:51
  • 基于Springboot和Redis实现的快递代取系统

    1.项目简介本项目基于springboot框架开发而成,前端采用bootstrap和layer框架开发,系统功能完整,界面简洁大方,比较适合做毕业设计使用。
    本项目主要实现了代取快递的信息管理功能,使用角色有三类:一是客户可以直接访问系统下单,输入代取快递的相关信息,并可以在系统中查询订单的完成进度,也可以对系统进行相应的反馈并查询反馈的回复情况。也可以直接在线支付代取费用。二是接单员,可以登陆系统进行接单,并根据自己的订单完成情况修改订单状态,查询自己的订单等。三是系统管理员,可以实现对人员和订单信息的管理,对反馈信息的回复等操作。
    1.1 开发运行环境
    开发工具:IDEA / ECLIPSE
    MYSQL: 5.7
    JDK:1.8
    Maven: 3.3.9
    后台技术:Spring boot+ SpringMVC + MyBatisPlus,连接池采用 Druid,安全框架使用 Shiro,缓存使用redis
    前台技术:Bootstrap + layer 实现

    1.2 需求分析学生下订单,代领人员接单,以学生给的取货码、姓名、电话、宿舍号等信息,代领人代领快递后送至宿舍,学生付款,代领人收款,结束订单。

    学生需要填写订单,包括姓名、电话、取货码、宿舍号、快递单号等。需要方便的查看自己的订单信息,包括下单时间、订单价格、签收时间、快递单号、快递内容、代领信息、付款方式等。同时能够确认每一单是否收到等问题,如果包裹出现问题,可以及时联系到代领人
    代领人需要接订单,并且知道订单的信息,包括姓名、电话、取货码、宿舍号、快递单号等。需要方便的查看自己完成的订单情况,包括每一单的收入及时间、下单信息等,同时能够确认每一单是否正常收款,如果未收到付款,可以及时联系到下单的学生

    1.3 数据流图

    1数据项名:学生姓名;类型:字符型;长度:20
    2数据项名:学生电话号码;类型:字符型;长度:11
    3数据项名:学生宿舍号;类型:字符型;长度:10
    4数据项名:订单号;类型:字符型;长度:20
    5数据项名:付款方式;类型:字符型;长度:20
    6数据项名:备注;类型:字符型;长度:100
    7数据项名:代领人姓名;类型:字符型;长度:20
    8数据项名:代领人电话号;类型:字符型;长度:11
    9数据项名:收款方式;类型:字符型;长度:20
    10数据项名:快递单号;类型:字符型;长度:20
    11数据项名:下单时间;类型:字符型;长度:20
    12数据项名:签收时间;类型:字符型;长度:20
    13数据项名:取货码;类型:字符型;长度:10
    14数据项名:价格;类型:字符型;长度:3
    15数据项名:快递内容;类型:字符型;长度:100

    2.数据库设计2.1 表结构用户表

    订单表

    2.2 E-R图
    3.项目开发3.1 工具类@Datapublic class JedisWrapper { public String host; public int port; public Jedis jedis = null; public Jedis getJedis(){ if(jedis==null){ jedis = new Jedis(host,port); } return jedis; }}
    C3P0连接池配置
    @Componentpublic class C3P0DataSourceFactory implements DataSourceFactory { @Qualifier("ds2") @Autowired DataSource dbcpDS; @Override public void setProperties(Properties props) { } @Override public DataSource getDataSource() { return dbcpDS; }}
    3.2 业务代码/** * 用户注册 * 情况1: 用户名已经被注册了 * 情况2: 正常注册 */@PostMapping(value = "/register")public Message register(@RequestBody UserDTO u, HttpServletResponse resp, HttpSession sess){ log.info("this is userDTO: {}",u); Message msg = userService.addUser(u,resp,sess); return msg;}/** * 用户登录: 需要返回 * 情况1: 用户名不存在 * 情况2: 用户名存在, 但是密码错误 * 情况3: 正确登录, 并注册一个session */@PostMapping(value = "/login")public Message login(@RequestBody UserDTO u, HttpServletResponse resp, HttpSession sess){ log.info("请求登录的-userDTO: {}",u); Message msg = userService.checkUser(u, resp, sess); return msg;}/** * 添加用户: 前端发个请求看看用户是否登录 * 情况1: 没有登录 * 情况2: 已经登录 */@RequestMapping(value = "/check")public Message check(HttpSession sess){ Message msg = userService.checkStatus(sess); return msg;}/** * 添加用户: 前端发个请求注销 */@RequestMapping(value = "/logout")public void logout(HttpSession sess){ log.info("用户:{} 已经注销",sess.getAttribute("username")); sess.invalidate();}
    订单业务
    /** * 用来测试的接口 */@RequestMapping(value = "/test", produces = "application/json")public String test(@RequestBody String s){ return "hello:"+s;}/** * 查询某个用户自己发起的订单 */@RequestMapping(value = "/own", produces = "application/json")public List<SelfOrderVO> getOwnOrders(HttpSession sess){ String username = (String)sess.getAttribute("username"); if(username==null){ log.warn("[查看我的订单] : session中没有用户名:还未登录"); return null; }else{ List<SelfOrderVO> orders = orderService.getOrdersByUsername(username); return orders; }}/** * 查询自己接的单子 */@RequestMapping(value="/picked")public List<SelfPickedOrderVO> getOwnPickedOrders(HttpSession sess){ String username = (String)sess.getAttribute("username"); if(username==null){ log.warn("[查看我的接单] : session中没有用户名:还未登录"); return null; }else{ List<SelfPickedOrderVO> orders = orderService.getPickedOrdersByUsername(username); return orders; }}/** * 提交订单 */@PostMapping(value = "/commit")public Message commit(@RequestBody OrderDTO orderDTO, HttpSession sess){ log.info("新订单为:{}",orderDTO); return orderService.addOrder(orderDTO,sess);}/** * 返回全部未接单的订单,在主页上显示 */@CrossOrigin(origins = "*")@GetMapping(value = "/all")public List<CommonOrderVO> getAllUnpickOrders(){ return orderService.getAllUnpickOrders();}/** * 获取订单详情 */@GetMapping(value = "/detail")public DetailOrderVO getDetailOrder(@RequestParam("orderId") int orderId) throws JsonProcessingException { log.info("请求订单号:{} 的详细信息",orderId); return orderService.getDetailOrder(orderId);}/** * 接单:只需要改订单的状态 */@RequestMapping(value = "/pick")public void pickOrder(@RequestParam("orderId") int orderId, HttpSession sess){ orderService.pickOrder(orderId, sess);}/** * 接单者-取消接单:只需要改订单的状态 */@RequestMapping(value = "/cancelPicked")public void cancelPickedOrder(@RequestParam("orderId") int orderId){ orderService.cancelPickedOrder(orderId);}/** * 接单者-确认送达 */@RequestMapping(value = "/confirmPicked")public void confirmPickedOrder(@RequestParam("orderId") int orderId){ orderService.confirmPickedOrder(orderId);}/** * 下单者-取消订单 */@RequestMapping(value = "/cancel")public void cancelOrder(@RequestParam("orderId") int orderId){ orderService.cancelOrder(orderId);}/** * 下单者-确认完成 */@RequestMapping(value = "/confirmCompleted")public void confirmOrder(@RequestParam("orderId") int orderId){ orderService.confirmOrder(orderId);}
    3.3 文件上传@RestController@CrossOriginpublic class FileController { @RequestMapping("/upload") public String upload(@RequestParam("file") MultipartFile file){ if (file.isEmpty()) { return "上传失败,请选择文件"; } String fileName = file.getOriginalFilename(); String filePath = "C:/Users/wyz/Desktop/"; File dest = new File(filePath + fileName); try { file.transferTo(dest); log.info("上传成功"); return "上传成功"; } catch (IOException e) { log.error(e.toString(), e); } return "上传失败!"; }}
    3.4 开发日志3.4.1 自定义Message码错误码

    1 登录:用户名不存在
    2 登录:密码错误
    3 注册:用户名已存在
    4 检查session:用户还未登录

    正确码

    1 登录成功
    2 注册成功
    3 用户已经登录

    3.4.2 自定义订单状态
    0:未接单 unpick
    1:已接单 pick
    2:已送达 arrived
    3:已完成 completed
    4:已取消 canceled
    5:已中止 terminated

    3.4.3 后端接收ajax数据今天遇到了一个很坑爹的问题:jquery的ajax传给后端的数据springboot居然接收不到
    servlet接收ajax
    因为springboot本质上是基于servlet的,所以看一下servlet接收ajax是什么样子的。
    用ajax的前端代码如下:

    正常用表单提交的方法如下:

    后端代码如下:

    用ajax发数据,结果如下:(好像第二行最前面少了一个问号?不知道表单提交的有没有)

    正常表单提交,结果如下:

    第二行为null是因为流只能读取一次。
    修改以下后端代码,看看用表单提交的话InputStream是什么样的:

    输出!

    fuck!我一开始还以为是最前面少了个问号的关系,结果正常用表单提交最前面也是没有问号的
    这个问题我没找到解决方法(似乎只能自己解析InputStream了?)
    ajax那边不管data的数据有没有加上JSON.stringify()都不行。
    山穷水尽疑无路 ,柳暗花明又一村
    我又回头搜了一下springboot和ajax,有了重大发现:
    springboot接收ajax

    ==注意画红框的这个类,这个类是需要可序列化的!!!==

    ==前端传json时,需要加上JSON.Stringify==

    3.4.4 ajax获取后端返回的数据又碰到一个坑。。。
    按理说ajax这么写就行了,我还特意加了 async:false 来取消异步

    结果前端执行的是error函数。。。
    后来发现:
    前端设置了希望后端发来的类型(dataType:”application/json”)
    但是后端没有设置返回类型
    把dataType删了就行!
    3.4.5 mybatis一级缓存的禁用因为mybatis有一级缓存,作同一个查询时,会复用上次的结果,自己通过cmd操作mysql(修改表中的数据),不会使缓存失效,只有通过mybatis修改数据,才会使一级缓存失效。
    所以怎么禁用一级缓存呢?
    配置文件
    mybatis: configuration: cache-enabled: false #禁用二级缓存 local-cache-scope: session #一级缓存指定为session级别 local-cache-scope: statement #一级缓存指定为statement级别, 相当于禁用一级缓存
    手动清除
    session.clearCache();
    4.项目展示登录

    首页

    接单


    发起订单


    个人中心

    购物车
    0  留言 2021-09-09 09:18:07
  • 基于springboot和layui实现的多法人社团管理系统

    1.项目简介1.1 目的和意义现如今大学社团各式各样的都有,学校对社团的管理手段处于落后阶段,以致于对社团的未来发展以及社团的活动开展都有一定的影响,导致大学校内社团不能健康的发展,所以有必要建设一个大学社团管理系统来帮助学校管理校内社团,给学校提供一个管理社团更有效的一个手段,本课题设计的就是一个大学社团管理系统,本系统的开发就是为学校提供一个监管大学社团的平台,为社团提供一个在线收纳社员的平台,为学生提供一个在线选择社团的平台,为每个用户提供全面且贴心的服务功能。
    随着高校的扩招,大学生群体不断壮大以及社团的多样化,学生社团这样一个学生组织也不断的壮大,高校社团文化日渐丰富,但当前我国高校学生社团发展中也存在不少问题,如“数量少”、“活动方式单一”、“资金短缺,物质条件较差”、“管理不规范”等一系列问题。如何更好地利用大学生社团的组织和活动,将其建设成为进行思想教育的有利阵地、学术探讨思想交流的第二课堂,是高校学生工作的一个重要课题。以及随之而来的繁琐的社团事务,使管理学生社团的工作变得不再那么容易,随着软件行业的发展,我们可以根据学生社团管理的需求来使用办公自动化来管理学生社团,介于社团事务的繁琐性,有必要开发这样一个系统来解决社团事务的繁琐性,提高办事效率。
    1.2 国内外的研究现状从上世纪五六十年代管理信息系统产生以来,管理信息系统理论发展得较为成熟。管理信息系统项目的实施对许多学校的发展起到了重要的作用。
    随着计算机网络技术的迅速普及,现在在全国大部分高校都将学校日常管理活动纳入到管理信息系统中。但通国外高校信息技术起步早、起点高的特点相比,中国许多高校的管理信息系统徒具其形,却管理混乱。因此,国内高校在管理信息方面需要提高自身的软实力。
    近年来,信息技术的突飞猛进,是的管理信息系统已经应用到大学管理中的各个领域当中,极大地提高了工作效率,因此开发一套完善的学生社团系统是十分必要的。对于社团管理的效率有很大的提高,并且可以节省人力、物力和财力,实现学校资源的最佳配置。
    1.3 主要研究内容系统整体架构
    管理员后台进行社团管理的操作以及审核状态的操作,然后用户进入前台选择查看和加入社团,等待管理员审核,管理员接收到消息并处理来达到两者间的交互。


    1.4 系统功能设计本系统主要分为管理员和学生两种用户。
    管理员功能如下:

    用户管理
    社团管理
    审核管理
    社联新闻管理


    用户功能如下:

    注册、登录
    查看社团、加入社团
    创建社团
    查看社团活动
    申请社团活动


    2.数据库设计2.1 表结构用户表

    权限表

    日志表

    管理员表
    ![](/upload/image/41223/345ac4fbc3ddbdcba5621793119fbbee.png)
    活动表

    社团表

    部门表

    物资表

    2.2 E-R图
    3.系统详细设计3.1 详细设计3.1.1 管理员
    管理员用户管理:对管理员用户进行修改操作
    社团管理:对社团进行管理,如:修改社团人员等操作
    审核管理:用户申请创建社团时,管理员审核并修改审核结果操作
    社联新闻管理:对社团的新闻进行管理,如:修改新闻内容等等

    3.1.2 用户
    用户管理:用户可以对自己的用户信息进行修改,如:修改密码等
    查看社团:用户可以查看社团目前成员,社团信息
    添加社团:用户选择社团进行加入,处于等待状态,待管理员审核后等待结果
    创建社团:对用户创建社团操作进行管理
    申请社团活动:对用户所申请社团活动的管理

    3.2 研究途径及技术路线主要特色
    通过实地调查本学校学生社团的运行现状,对系统开发进行可行性分析和需求分析,并深入了解业务流程和数据流程,在此基础上得出初步的开发方案,继而进行系统设计。该系统采用面向对象的程序设计方法,该方法是一种基于结构分析的以数据为中心的程序设计方法,其主要思想是将数据及处理这些数据的操作都封装在一个叫做类的数据结构里。这种方法描述的现实世界模型贴切、合理,更符合人们认识世界的思维方法。
    涉及主要技术

    后台框架:SSM SSM框架集由SpringBoot、MyBatis两个开源框架整合而成
    数据库技术:MySQL
    安全框架:shiro
    前台框架:主要采用Layui,html,css,JavaScript等技术

    3.3 项目接口文档3.3.1 社团事务事务插入
    POST请求:{ "oid":"1", "uid":"201641413117", "priority":0, "createTime":"", "status":1, "tips":"音乐社设计"}返回:{ "code": 0, "msg": "成功", "data": "事务插入成功"}
    事务删除
    GET请求:http://localhost:8080/api/organAffair/deleteDepartmentById?id=2{ "code": 0, "msg": "成功", "data": "事务删除成功"}{ "code": -1, "msg": "事务删除失败", "data": null}
    事务更新
    POST请求:http://localhost:8080/api/organAffair/updateOrganAffair{ "id":1, "oid":"1", "uid":"201641413117", "priority":0, "createTime":"", "status":0, "tips":"音乐社设计"}{ "code": 0, "msg": "成功", "data": "事务更新成功"}
    事务获取
    GET请求:http://localhost:8080/api/organAffair/getOrganAffairList?oid=1&current=1&size=2返回{ "pages": 1, "current": 1, "total": 1, "data": [ { "id": 1, "oid": 1, "uid": "201641413418", "priority": 0, "logname": "音乐社团测试", "createTime": "2019-09-18T15:58:16.000+0000", "status": 0, "tips": "音乐社设计" } ]}
    3.3.2 社团团体名字模糊查询GET:http://localhost:8080/api/organ/queryOrganListByName?name=篮球返回:{ "pages":1, "current":1, "total":2, "data":[ { "id":1, "name":"篮球社", "create_date":null, "nums":120, "level":3, "details":"篮球火" }, { "id":2, "name":"篮球社", "create_date":null, "nums":0, "level":3, "details":"篮球火" } ]}GET http://localhost:8080/api/organ/queryOrganListById?id=1返回:{ "id":1, "name":"篮球社", "create_date":null, "nums":120, "level":3, "details":"篮球火"}无条件获取列表GET http://localhost:8080/api/organ/queryOrganList{ "pages":1, "current":1, "total":2, "data":[ { "id":1, "name":"篮球社", "create_date":null, "nums":120, "level":3, "details":"篮球火" }, { "id":2, "name":"篮球社", "create_date":null, "nums":0, "level":3, "details":"篮球火" } ]}根据社团ID删除GET http://localhost:8080/api/organ/deleteOrgan?id=1返回{ "code":0, "msg":"成功", "data":"社团删除成功"}更新社团 POST http://localhost:8080//api/organ/updateOrgan{ "oid":2, "name":"篮球社", "create_date":"2019年八月"}返回:{ "code":0, "msg":"成功", "data":"社团更新成功"}插入社团:POST http://localhost:8080//api/organ/insertOrgan{ "oid":3, "name":"游泳社", "create_date":"2019年八月", "level":1, "details":"游泳"}返回:{ "code":0, "msg":"成功", "data":"社团插入成功"}
    3.3.3 社团物资管理name模糊查询GET http://localhost:8080/api/goods/queryGoodsListByName?name=ball返回:{ "pages":1, "current":1, "total":2, "data":[ { "id":1, "oid":1, "name":"money", "nums":"1", "price":"100", "tips":"test" }, { "id":2, "oid":2, "name":"ball", "nums":"2", "price":"200", "tips":"test" } ]}根据oid查询GET http://localhost:8080/api/goods/queryGoodsListByOid?oid=1返回:{ "id":1, "oid":1, "name":"money", "nums":"1", "price":"100", "tips":"test"}无条件获取列表GET http://localhost:8080/api/goods/queryGoodsList返回:{ "pages":1, "current":1, "total":2, "data":[ { "id":1, "oid":1, "name":"money", "nums":"1", "price":"100", "tips":"test" }, { "id":2, "oid":2, "name":"ball", "nums":"2", "price":"200", "tips":"test" } ]}根据社团物资ID删除GET http://localhost:8080/api/goods/deleteGoods?oid=2返回:{ "code":0, "msg":"成功", "data":"社团删除成功"}更新社团:POST http://localhost:8080//api/goods/UpdateGoods{ "oid":1, "name":"ball"}返回:{ "code":0, "msg":"成功", "data":"物资更新成功"}插入社团:POST http://localhost:8080//api/goods/InsertGoods{ "oid":"4", "name":"desk", "nums":"5", "price":5, "tips":"test", "id":"4"}返回:{ "code":0, "msg":"成功", "data":"物资插入成功"}
    3.3.4 社团进行中活动查询current当前页size 每页条数默认10 GET http://localhost:8080/api/organ/activity/getOrganActivityListActive?&current=1&size=2{ "code":0, "pages":1, "current":1, "total":1, "data":[ { "id":1, "oid":1, "name":"音乐社", "title":"十大歌手", "details":"唱歌", "status":1 } ]}GET http://localhost:8080/api/organ/affair/getOrganAffairListByUid?uid=201641413417&current=1&size=10{ "code":0, "pages":1, "current":1, "total":3, "data":[ { "id":1, "oid":1, "uid":"201641413417", "priority":1, "logname":"加入社团", "createTime":"2019-10-08 10:47:01", "status":1, "tips":"篮球社" }, { "id":2, "oid":1, "uid":"201641413417", "priority":1, "logname":"参加活动", "createTime":"2019-10-08 15:29:04", "status":1, "tips":"篮球社" }, { "id":3, "oid":1, "uid":"201641413417", "priority":1, "logname":"参加活动", "createTime":"2019-10-08 15:29:12", "status":1, "tips":"篮球社" } ]}
    3.4 工具类时间工具
    /** * 时间转换 */public class DateTimeConvert { public static final String STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss"; // str to date public static Date strToDate(String str, String pattern) { if (StringUtils.isBlank(str)) { return null; } DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(pattern); DateTime dateTime = dateTimeFormatter.parseDateTime(str); return dateTime.toDate(); } // common str to data public static Date strToDate(String str) { if (StringUtils.isBlank(str)) { return null; } DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(STANDARD_FORMAT); DateTime dateTime = dateTimeFormatter.parseDateTime(str); return dateTime.toDate(); } // date to str public static String dateToStr(Date date, String pattern) { if (date == null) { return StringUtils.EMPTY; } DateTime dateTime = new DateTime(date); return dateTime.toString(pattern); } // common date to str public static String dateToStr(Date date) { if (date == null) { return StringUtils.EMPTY; } DateTime dateTime = new DateTime(date); return dateTime.toString(STANDARD_FORMAT); }}
    日志处理工具类
    /** * 日志处理工具类 */public class LogUtil { public static Log getLog(String type, String operate, String result, HttpServletRequest request){ Log log = new Log(); Date date = new Date(); String ip = IPUtil.getIpAddr(request); // 该属性在检查token的时候已经放入 HttpSession session = request.getSession(); String account = (String)session.getAttribute("account"); // 若果登录失败则为null,设置为-1 if(account == null){ account = "非法用户"; } log.setMessage(operate); log.setAccount(account); log.setCreateTime(date); log.setIp(ip); log.setLogname(type); log.setSucceed(result); return log; }}
    拦截器配置
    @Override protected void configure(HttpSecurity http) throws Exception { http.headers().frameOptions().sameOrigin(); http.authorizeRequests() .antMatchers("/api/admin/**").hasAnyRole("admin","student") .antMatchers("/api/organ/**").hasAnyRole("student","admin") .antMatchers("/Student/**").hasRole("student") .antMatchers("/api/student/**").hasRole("student") .antMatchers("/layui/**").permitAll() .antMatchers("/WeAdmin/**").permitAll() .antMatchers("/Student/**").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/WeAdmin/login.html") .loginProcessingUrl("/login").permitAll() .usernameParameter("username") .passwordParameter("passwd") .successHandler(new AuthenticationSuccessHandler() { @Override public void onAuthenticationSuccess(HttpServletRequest Request, HttpServletResponse Response, Authentication authentication) throws IOException, ServletException { HttpSession session = Request.getSession(); Account account = (Account) SecurityContextHolder.getContext() .getAuthentication() .getPrincipal(); System.out.println(account.getPassword()); session.setAttribute("account",account.getUsername()); logService.insertLog(LogUtil.getLog("登录日志","登陆成功","操作成功",Request)); Object principal = authentication.getPrincipal(); if(account.getRoleid() == 1) Response.sendRedirect("/WeAdmin/index.html"); else Response.sendRedirect("/Student/navbar.html"); } }) .failureHandler(new AuthenticationFailureHandler() { @Override public void onAuthenticationFailure(HttpServletRequest Request, HttpServletResponse Response, AuthenticationException e) throws IOException, ServletException { Response.setContentType("application/json;charset=utf-8"); PrintWriter out = Response.getWriter(); Response.setStatus(401); Map<String, Object> map = new HashMap<>(); ObjectMapper om = new ObjectMapper(); map.put("status",401); if(e instanceof BadCredentialsException){ map.put("msg","账号或密码错误"); }else{ map.put("msg","登陆失败"); } out.write(om.writeValueAsString(map)); out.flush(); out.close(); } }) .and() .logout() .logoutUrl("/logout") .clearAuthentication(true) .invalidateHttpSession(true) .addLogoutHandler(new LogoutHandler() { @Override public void logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) { } }) .logoutSuccessHandler(new LogoutSuccessHandler() { @Override public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { httpServletResponse.sendRedirect("/login.html"); } }) .permitAll() .and() .csrf().disable(); } @Bean PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Override protected void configure(AuthenticationManagerBuilder auth)throws Exception{ auth.userDetailsService(accountService); } /** 放行静态资源 */ @Override public void configure(WebSecurity web) throws Exception { //解决静态资源被拦截的问题 web.ignoring().antMatchers("/css/**"); web.ignoring().antMatchers("/page/**"); web.ignoring().antMatchers("/js/**"); web.ignoring().antMatchers("/layui/**"); web.ignoring().antMatchers("/images/**"); web.ignoring().antMatchers("/WeAdmin/**"); }}
    3.5 业务代码@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { //获取账户信息 QueryWrapper<Account> wrapper = new QueryWrapper<Account>(); wrapper.eq("account",s); Account account = accountMapper.selectOne(wrapper); System.out.println(account.getPassword()); if(account == null){ throw new UsernameNotFoundException("账户不存在"); } //获取角色ID int id = account.getRoleid(); QueryWrapper<Role> rwrapper = new QueryWrapper<Role>(); rwrapper.eq("id",id); //设置角色 account.setRole(roleMapper.selectOne(rwrapper)); return account;}//获取管理员信息public ResponsePage<Account> queryAccount(String s){ QueryWrapper<Account> wrapper = new QueryWrapper<Account>(); System.out.println("传入名字:"+s); wrapper.eq("account",s); Account account = accountMapper.selectOne(wrapper); if (account == null){ ResponsePage<Account> responsePage= new ResponsePage<Account>(); responsePage.setTotal(10); responsePage.setCode(0); responsePage.setCurrent(1); List<Account> l = new LinkedList<Account>(); responsePage.setData(l); return responsePage; } //获取角色ID int id = account.getRoleid(); QueryWrapper<Role> rwrapper = new QueryWrapper<Role>(); rwrapper.eq("id",id); //设置角色 account.setRole(roleMapper.selectOne(rwrapper)); ResponsePage<Account> responsePage= new ResponsePage<Account>(); responsePage.setTotal(10); responsePage.setCode(0); responsePage.setCurrent(1); List<Account> l = new LinkedList<Account>(); l.add(account); responsePage.setData(l); return responsePage;}/** * ID获取管理员信息 * @param id * @return*/public Account queryAccountById(int id){ return accountMapper.selectById(id);}/** * 获取管理员列表 * @param current * @param size * @return*/public ResponsePage<Account> queryAccountList(int current, int size){ Page<Account> page = new Page<Account>(current, size); IPage<Account> iPage = accountMapper.selectPage(page,null); ResponsePage<Account> responsePage= new ResponsePage<Account>(); responsePage.makePage(iPage); return responsePage;}/** * 插入管理员 * @param account * @return*/public int insertAccount(Account account){ account.setCreateTime(new Date()); account.setModifyTime(new Date()); int result = accountMapper.insert(account); return result;}/** * 删除管理员 * @param id * @return*/public int deleteAccount(int id){ int result = accountMapper.deleteById(id); return result;}/** * 更新管理员 * @param account * @return*/public int updateAccount(Account account){ QueryWrapper<Account> wrapper = new QueryWrapper<Account>(); wrapper.eq("id",account.getId()); account.setModifyTime(new Date()); int result = accountMapper.update(account,wrapper); return result;}/** * 重置密码 * @param oldpass * @param newpass * @param account*/public Boolean resetPasswd(String oldpass,String newpass,String account){ QueryWrapper<Account> wrapper = new QueryWrapper<Account>(); wrapper.eq("account",account); Account account1 = accountMapper.selectOne(wrapper); PasswordEncoder password = new BCryptPasswordEncoder(); if( password.matches(oldpass, account1.getPassword())) { account1.setPassword(password.encode(newpass)); accountMapper.updateById(account1); return true; }else { return false; }}
    4.项目展示4.1 普通用户首页

    活动列表


    模糊查询

    社团列表


    个人信息

    4.2 教师用户
    4.3 管理员用户首页

    社团管理

    成员管理

    活动管理

    事务管理

    导出功能

    物资管理

    用户管理

    日志管理

    5.主要参考文献。[1] 萨师煊,王珊编著.数据库系统概论(第四版).北京:高等教育出版社.,ISBN 978-7-04-019583-5
    [2] 周洋,何丽丽.基于B/S模式的高校社团管理系统的研究与设计[J].电脑知识与技术,2018,14(33):84-85+96.
    [3] 韩璐. 高校学生社团管理系统的设计与实现[D].电子科技大学,2019.
    [4] 龚文辉. 高校大学生社团管理平台的设计与实现[D].江西师范大学,2018.
    [5] 郝平.学生社团管理系统设计与实现研究[J].电脑迷,2018(02):26.
    [6] 石志国刘翼伟王志良编著 JSP应用教程(修订本),清华大学出版社,北京交通大学出版社2008.6
    [7] 袁鹏飞,孙君安.中文版SQL Server2005数据库系统管理.北京:人民邮电出版社,2001
    [8] 郑阿奇主编,刘启芬,顾韵华.SQL Server实用教程(第2版).北京:电子工业出版社. 7,202-203
    [9] 王军牛志玲译 SQL Server 2012编程入门经典(第4版)清华大学出版社 2013,4
    0  留言 2021-09-07 14:25:40
  • 基于springboot和Themleaf实现的个人博客系统

    1.项目简介该项目试基于SpringBoot2.X+Thymeleaf 实现的完整博客系统。
    部分的前端展示页面和css样式等借鉴了部分网络作者的开源项目,在此向其作者表示感谢!
    因为博主的能力有限,重构计划一直拖后,但是对于自己项目的目标还是有的:未来计划后台采用vuejs,前台选用更加清晰的模板引擎,在整体的项目基础上实现前后端分离,使用Redis中间件做缓存。
    1.1 博客特点
    使用现如今流行的java语言及springboot框架开发,体系完整,结构清晰,是一套不错的学习项目
    整体的后端开发模式使用MVC,分层清楚,逻辑清楚,适合学者参考学习
    在博客的文档编辑、博客目录的生成与展示等地方使用了开源插件,实现了动态的js和对于makedown文档的编辑支持,整体上符合现如今流行的博客编辑器。

    1.2 功能介绍本博客系统基于 SpringBoot 2.x,支持快速开发,部署,服务器采用tomcat。
    数据库采用常见的关系型数据库Mysql,ORM框架采用JPA
    模板引擎采用Thymeleaf (对于为何使用Thymeleaf 作为模板引擎,可以阅读此文章为何选择Thymeleaf),由于精力及能力有限没有采用vue,在后期更新中考虑后台改为vue实现,敬请期待!
    博客功能导图

    1.3 整体功能前台部分

    首页:展示博客、展示所有的分类及标签、点击进入博客详情
    分类:类型对博客进行划分并分别展示
    标签:按标签对博客进行划分与展示
    时间轴:根据文章发布的时间形成一个时间轴
    照片墙: 记录自己的生活
    归档:整体按照年份对博客进行归档,可以进行博客内容查询
    关于我:展示博主有关信息

    后台部分(管理员部分)

    博客管理:实现博客的增删改查
    分类管理:实现分类的增删改查
    标签管理:实现标签的增删改查

    整体架构
    博客系统整体分层如下:

    1.4 页面预览
    2.数据库设计2.1 表结构文章表

    评论表

    消息表

    照片表

    分类表

    用户表

    2.2 E-R图
    3.准备工作两个星期前,我想做一个博客。于是找到资料,并开始搬砖。

    Spring学习:理解IOC(控制反转)和AOP(面向切面编程)

    https://blog.csdn.net/qq_22583741/article/details/79589910
    Maven学习:添加依赖,坐标定义(groupId,artifactId,version),pom基本配置

    https://blog.csdn.net/weisg81/article/details/76795190
    SpringBoot学习:采用gradle框架,和Maven一样是自动构建工具。一样是采用SpringMVC的设计模式

    https://blog.csdn.net/qq_22860341/article/details/79173580
    Themleaf学习:前端框架

    https://blog.csdn.net/u012706811/article/details/52185345
    Spring Data jpa:已封装好增删改查的方法,可以直接调用

    https://blog.csdn.net/tyyytcj/article/details/76281836

    4.项目实现4.1 controller包包括管理员,博客,分类,评论,主页,用户,用户主页,点赞这八大块功能的实现。

    @Controller@RequestMapping("/admin")public class BlogController { @Autowired private BlogService blogService; @Autowired private TypeService typeService; //跳转到博客列表页 @GetMapping("/blogs") public String blogs(Model model, @RequestParam(defaultValue = "1",value = "pageNum") Integer pageNum){ String orderBy = "t_blog.update_time desc"; PageHelper.startPage(pageNum,10,orderBy); List<Blog> allBlog = blogService.getAllBlog(); PageInfo<Blog> pageInfo = new PageInfo<>(allBlog); model.addAttribute("pageInfo",pageInfo); List<Type> allType = typeService.getAllType(); model.addAttribute("allType",allType); return "admin/blogs"; } //博客搜索 @PostMapping("/blogs/search") public String blogsSearch(Model model, @RequestParam(defaultValue = "1",value = "pageNum") Integer pageNum, SearchBlog blog){ String orderBy = "t_blog.update_time desc"; PageHelper.startPage(pageNum,10,orderBy); List<Blog> allBlog = blogService.getBlogByConditions(blog); PageInfo<Blog> pageInfo = new PageInfo<>(allBlog); model.addAttribute("pageInfo",pageInfo); model.addAttribute("blogSearch",blog); return "admin/blogs-search :: blogList"; } //博客搜索-分页处理 @GetMapping("/blogs/search") public String blogsSearchPage(Model model, @RequestParam(defaultValue = "1",value = "pageNum") Integer pageNum, SearchBlog blog ){ String orderBy = "t_blog.update_time desc"; PageHelper.startPage(pageNum,10,orderBy); List<Blog> allBlog = blogService.getBlogByConditions(blog); PageInfo<Blog> pageInfo = new PageInfo<>(allBlog); model.addAttribute("pageInfo",pageInfo); model.addAttribute("blogSearch",blog);// return "admin/blogs-search :: blogList"; return "admin/blogs-search"; } //新增博客页面跳转 @GetMapping("/blogs/input") public String blogInput(Model model){ model.addAttribute("types",typeService.getAllType()); Blog blog = new Blog(); blog.setType(new Type()); model.addAttribute("blog",blog); return "admin/blogs-input"; } //博客编辑页面跳转 @GetMapping("/blogs/{id}/input") public String blogEdit(Model model,@PathVariable Long id){ model.addAttribute("types",typeService.getAllType()); model.addAttribute("blog",blogService.getBlogById(id)); return "admin/blogs-input"; } //新增操作 @PostMapping("/blogs") public String post(Blog blog, HttpSession session, RedirectAttributes attributes){ User curUser = (User) session.getAttribute("user");// blog.setUser(curUser); blog.setUserId(curUser.getId());// blog.setType(typeService.getTypeById(blog.getTypeId())); int res = blogService.saveBlog(blog); if(res == 0){ attributes.addFlashAttribute("message","提示:操作失败"); }else{ attributes.addFlashAttribute("message","提示:操作成功"); } return "redirect:/admin/blogs"; } //编辑操作 @PostMapping("/blogs/edit") public String postEdit(Blog blog, HttpSession session, RedirectAttributes attributes){ User curUser = (User) session.getAttribute("user");// blog.setUser(curUser); blog.setUserId(curUser.getId());// blog.setType(typeService.getTypeById(blog.getTypeId())); int res = blogService.updateBlog(blog); if(res == 0){ attributes.addFlashAttribute("message","提示:操作失败"); }else{ attributes.addFlashAttribute("message","提示:操作成功"); } return "redirect:/admin/blogs"; } //删除操作 @GetMapping("/blogs/{id}/delete") public String deleteBlog(@PathVariable Long id){ blogService.deleteBlog(id); return "redirect:/admin/blogs"; }}
    4.2 工具类批量异常处理器
    @ControllerAdvice //是一个拦截所有标有controller注解的控制器public class ControllerExceptionHandler { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @ExceptionHandler(Exception.class) public ModelAndView exceptionHandler(HttpServletRequest request,Exception e) throws Exception { logger.error("Request URL : {}, Exception : {}",request.getRequestURL(),e); if(AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null){ throw e; } ModelAndView mv = new ModelAndView(); mv.addObject("url",request.getRequestURL()); mv.addObject("exception",e); mv.setViewName("error/error"); return mv; }
    加密工具
    public class MD5Utils { /** * @Description: MD5加密 * @Auther: xlw * @Date: 10:35 2020/3/27 * @Param: 要加密的字符串 * @Return: 加密后的字符串 */ public static String code(String str){ try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(str.getBytes()); byte[]byteDigest = md.digest(); int i; StringBuffer buf = new StringBuffer(""); for (int offset = 0; offset < byteDigest.length; offset++) { i = byteDigest[offset]; if (i < 0) i += 256; if (i < 16) buf.append("0"); buf.append(Integer.toHexString(i)); } //32位加密 return buf.toString(); // 16位的加密 //return buf.toString().substring(8, 24); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } }
    Makrdown工具类
    public class MarkdownUtils { /** * markdown格式转换成HTML格式 * @param markdown * @return */ public static String markdownToHtml(String markdown) { Parser parser = Parser.builder().build(); Node document = parser.parse(markdown); HtmlRenderer renderer = HtmlRenderer.builder().build(); return renderer.render(document); } /** * 增加扩展[标题锚点,表格生成] * Markdown转换成HTML * @param markdown * @return */ public static String markdownToHtmlExtensions(String markdown) { //h标题生成id Set<Extension> headingAnchorExtensions = Collections.singleton(HeadingAnchorExtension.create()); //转换table的HTML List<Extension> tableExtension = Arrays.asList(TablesExtension.create()); Parser parser = Parser.builder() .extensions(tableExtension) .build(); Node document = parser.parse(markdown); HtmlRenderer renderer = HtmlRenderer.builder() .extensions(headingAnchorExtensions) .extensions(tableExtension) .attributeProviderFactory(new AttributeProviderFactory() { public AttributeProvider create(AttributeProviderContext context) { return new CustomAttributeProvider(); } }) .build(); return renderer.render(document); } /** * 处理标签的属性 */ static class CustomAttributeProvider implements AttributeProvider { @Override public void setAttributes(Node node, String tagName, Map<String, String> attributes) { //改变a标签的target属性为_blank if (node instanceof Link) { attributes.put("target", "_blank"); } if (node instanceof TableBlock) { attributes.put("class", "ui celled table"); } } } public static void main(String[] args) { String table = "| hello | hi | 哈哈哈 |\n" + "| ----- | ---- | ----- |\n" + "| 斯维尔多 | 士大夫 | f啊 |\n" + "| 阿什顿发 | 非固定杆 | 撒阿什顿发 |\n" + "\n"; String a = "[ONESTAR](http://122.51.28.187:8080/)"; System.out.println(markdownToHtmlExtensions(a)); }}
    5.项目展示5.1 前端主页


    首页底部

    文章详情

    评论

    文章分类

    时间轴

    音乐盒

    留言板

    照片墙

    关于我

    5.2 后管登录

    主页

    文章管理

    发布文章

    分类管理

    相册管理
    1  留言 2021-09-06 10:47:41
  • 基于SSM和Mysql实现的图书管理系统

    基于SSM框架的客户管理系统设计与实现
    1.项目简介一个简单的客户关系管理系统,管理客户的基本数据、客户的分配、客户的流失以及客户的状态。
    项目亮点:

    基于角色访问控制(RBAC)设计的权限AOP日志系统Shiro后端url鉴权、方法鉴权Excel导入导出示例
    1.1技术栈SSM + Jdk1.8 + MySql5.4
    1.2运行环境Ecplice + Jdk1.8 + Tomcat
    2.数据库设计2.1表结构客户信息表

    日志表

    员工表

    权限表

    菜单表

    2.2ER图
    3.项目实现3.1项目配置<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration> <settings><!-- 启用二级缓存 --> <setting name="cacheEnabled" value="true"/><!-- 启用延迟加载波 --> <setting name="lazyLoadingEnabled" value="true" /> <setting name="aggressiveLazyLoading" value="false" /> </settings> <!-- 别名 --> <typeAliases> <package name="com.entity"/> </typeAliases> <!-- 引用映射文件 --> <mappers> <mapper resource="com/mapper/KhClientinfoMapper.xml" /> <mapper resource="com/mapper/YhEmployeeMapper.xml" /> <mapper resource="com/mapper/YhRoleMapper.xml" /> <mapper resource="com/mapper/YhRolerootMapper.xml" /> <mapper resource="com/mapper/YhRootMapper.xml" /> <mapper resource="com/mapper/KhHuiMapper.xml" /> <mapper resource="com/mapper/LogMapper.xml" /> <mapper resource="com/mapper/LogsMapper.xml" /> </mappers></configuration>
    依赖配置
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.maven</groupId> <artifactId>ssmClient</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>ssmClient Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.2.3</version> </dependency> <!-- mybatis-spring 整合 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.2.2</version> </dependency> <!-- spring相关依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>3.1.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>3.1.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>3.1.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>3.1.1.RELEASE</version> </dependency> <!-- 延时加载/cglib --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2</version> </dependency> <!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.10</version> </dependency> <!-- 数据源 --> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.2.2</version> </dependency> <!-- jstl --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- log --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.7</version> </dependency> <!-- spring aop相关依赖 --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.11</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.10</version> </dependency> <!-- javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!-- spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>3.1.2.RELEASE</version> </dependency> <!-- commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.2.2</version> </dependency> <!-- commons-io图片上传 --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.2</version> </dependency> <!-- https://mvnrepository.com/artifact/net.sourceforge.jexcelapi/jxl --> <!--xls导入导出没目录 --> <dependency> <groupId>net.sourceforge.jexcelapi</groupId> <artifactId>jxl</artifactId> <version>2.6.12</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.poi/poi --> <!--xls导出下载有目录的 --><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.6</version></dependency> </dependencies> <build> <finalName>ssmClient</finalName> </build></project>
    3.2工具类加密工具
    /* * MD5加密 */public class MD5 { public static String encrypt(String data) { String encrypt = ""; try { // 在程序中选择MD5加密算法 MessageDigest messageDigest = MessageDigest.getInstance("MD5"); //使用MD5加密算法对明文数据进行加密 byte[] result = messageDigest.digest(data.getBytes()); //加密后的字节数据数据转换为密文字符串(十六制) for(int i = 0;i<result.length;i++){ encrypt+=Integer.toHexString(result[i] & 0xff); } } catch (Exception e) { e.printStackTrace(); } return encrypt.toUpperCase(); }}
    封装页面显示逻辑
    //封装页面显示逻辑public class Pagination{ private int total;// 总共的数据量 private int pageSize;// 每页显示多少条 private int totalPage;// 共有多少页 private int index;// 当前是第几页 private List data; // 数据 private String path;// 连接路径
    3.3客户信息package com.controller;import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.List;import java.util.Map;import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest;import org.springframework.stereotype.Controller;import org.springframework.ui.ModelMap;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import com.dao.KhClientinfoMapper;import com.dao.KhHuiMapper;import com.dao.LogsMapper;import com.entity.KhClientinfo;import com.entity.KhHui;import com.entity.Logs;import com.util.Pagination;@Controller@RequestMapping("/khclient")public class KhClientinfoController extends BaseController{ @Resource//客户表 KhClientinfoMapper khclientDao; @Resource//客户跟进表 KhHuiMapper khhuiDao; @Resource LogsMapper logsDao; //客户表显示 @RequestMapping("/show") public String show(Integer index,HttpServletRequest request) { int pageNO = 1; if(index!=null){ pageNO = index; } String names = (String) request.getSession().getAttribute("name"); String relo = (String) request.getSession().getAttribute("relo"); Pagination pager = new Pagination(); Map params = new HashMap(); params.put("start", (pageNO-1)*40); params.put("pagesize", 40); if("客服".equals(relo)) { params.put("kefuname", names); } List all = khclientDao.show(params); pager.setData(all); pager.setIndex(pageNO); request.getSession().setAttribute("pageNO", pager.getIndex()); pager.setPageSize(40); pager.setTotal(khclientDao.getTotal()); pager.setPath("show.do?"); request.setAttribute("pager", pager); return "client/cl-show"; } //客户表新建 @RequestMapping(value = "/add") public String add(KhClientinfo data,HttpServletRequest request) { Date now = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");//设置时间显示格式 String str = sdf.format(now); String names = (String) request.getSession().getAttribute("name"); data.setKehuday(str); data.setKefuname(names); data.setKhstate("未到访"); Date time = null; if ("A:已交房客户".equals(data.getKehulei())) { time= new Date(now.getTime() + (long)3 * 24 * 60 * 60 * 1000);//加3天 } if ("B:3个月内交房客户".equals(data.getKehulei())) { time= new Date(now.getTime() + (long)7 * 24 * 60 * 60 * 1000);//加7天 } if ("C:3-6交房客户".equals(data.getKehulei())) { time= new Date(now.getTime() + (long)15 * 24 * 60 * 60 * 1000);//加15天 } if ("D:6个月以上交房客户".equals(data.getKehulei())) { time= new Date(now.getTime() + (long)30 * 24 * 60 * 60 * 1000);//加30天 } String stc = sdf.format(time); if (data.getKehutel().length()>1) { KhClientinfo khClient=khclientDao.tel(data.getKehutel()); if (khClient!=null) { request.setAttribute("all", khClient.getKefuname()); return "client/chongfu"; } } khclientDao.insertSelective(data); KhClientinfo khClientinfo=khclientDao.isdn(); KhHui khHui=new KhHui(); khHui.setYuday(stc); khHui.setWenti("客户第一次跟进"); khHui.setInid(khClientinfo.getId()); khHui.setScday(str); khhuiDao.insertSelective(khHui); Integer pagerNO=(Integer)request.getSession().getAttribute("pageNO"); return "redirect:/khclient/show?index="+pagerNO; } //客户表删除 @RequestMapping("/{id}/del") public String del(@PathVariable("id") int id,HttpServletRequest request) { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 时间字符串产生方式 String uid = format.format(new Date()); String names = (String) request.getSession().getAttribute("name"); KhClientinfo khClientinfo=khclientDao.selectByPrimaryKey(id); Logs logs =new Logs(); logs.setDay(uid); logs.setLoname(names); logs.setLei("删除"); logs.setBiaoid(khClientinfo.getKuhuname()+"+"+khClientinfo.getKehutel()); logs.setBiao("客户表及跟进详情"); logsDao.insertSelective(logs); khclientDao.deleteByPrimaryKey(id); Integer pagerNO=(Integer)request.getSession().getAttribute("pageNO"); String like=request.getParameter("like"); if (like!=null&&like.length()>0) { return "redirect:/khclient/like?index="+pagerNO; }else { return "redirect:/khclient/show?index="+pagerNO; } } //客户表编辑前取数据 @RequestMapping("/{id}/load") public String load(@PathVariable("id") int id,HttpServletRequest request, ModelMap model) { KhClientinfo record = (KhClientinfo) khclientDao.selectByPrimaryKey(id); model.addAttribute("record", record); String like=request.getParameter("like"); if (like!=null) { request.setAttribute("like", like); } return "client/cl-modify"; } //客户表编辑 @RequestMapping(value = "/update") public String update(KhClientinfo data,HttpServletRequest request) { khclientDao.updateByPrimaryKeySelective(data); Integer pagerNO=(Integer)request.getSession().getAttribute("pageNO"); String like=request.getParameter("like"); if (like!=null&&like.length()>0) { return "redirect:/khclient/like?index="+pagerNO; }else { return "redirect:/khclient/show?index="+pagerNO; } } //客户表模糊查找 @RequestMapping("/like") public String like(Integer index, KhClientinfo data,HttpServletRequest request) { int pageNO = 1; if(index!=null){ pageNO = index; } Pagination pager = new Pagination(); Map params = new HashMap(); String lk=request.getParameter("lk"); String names = (String) request.getSession().getAttribute("name"); String relo = (String) request.getSession().getAttribute("relo"); if (lk!=null&&lk.length()>0) { request.getSession().setAttribute("kuhuname",data.getKuhuname()); request.getSession().setAttribute("kehuaddres",data.getKehuaddres()); request.getSession().setAttribute("kehutel",data.getKehutel()); request.getSession().setAttribute("kehulei",data.getKehulei()); request.getSession().setAttribute("kehugenre",data.getKehugenre()); request.getSession().setAttribute("kaiday",data.getKaiday()); request.getSession().setAttribute("weixin",data.getWeixin()); request.getSession().setAttribute("channel",data.getChannel()); request.getSession().setAttribute("khstate",data.getKhstate()); request.getSession().setAttribute("kefuname",data.getKefuname()); request.getSession().setAttribute("kehuday",data.getKehuday()); request.getSession().setAttribute("qu",data.getQu()); request.getSession().setAttribute("an",data.getAn()); request.getSession().setAttribute("jiename",data.getJiename()); } String qu= (String) request.getSession().getAttribute("qu"); if(qu!=null&&qu.length()>0) { params.put("qu", qu); } String an= (String) request.getSession().getAttribute("an"); if(an!=null&&an.length()>0) { params.put("an", an); } String jiename= (String) request.getSession().getAttribute("jiename"); if(jiename!=null&&jiename.length()>0) { params.put("jiename", jiename); } String kaiday= (String) request.getSession().getAttribute("kaiday"); if(kaiday!=null&&kaiday.length()>0) { params.put("kaiday", kaiday); } String weixin= (String) request.getSession().getAttribute("weixin"); if(weixin!=null&&weixin.length()>0) { params.put("weixin", weixin); } String channel= (String) request.getSession().getAttribute("channel"); if(channel!=null&&channel.length()>0) { params.put("channel", channel); } String khstate= (String) request.getSession().getAttribute("khstate"); if(khstate!=null&&khstate.length()>0) { params.put("khstate", khstate); } String kehuday= (String) request.getSession().getAttribute("kehuday"); if(kehuday!=null&&kehuday.length()>0) { params.put("kehuday", kehuday); } String kuhuname= (String) request.getSession().getAttribute("kuhuname"); if(kuhuname!=null&&kuhuname.length()>0) { params.put("kuhuname", kuhuname); } String kehuaddres= (String) request.getSession().getAttribute("kehuaddres"); if(kehuaddres!=null&&kehuaddres.length()>0) { params.put("kehuaddres", kehuaddres); } String kehugenre= (String) request.getSession().getAttribute("kehugenre"); if(kehugenre!=null&&kehugenre.length()>0) { params.put("kehugenre", kehugenre); } String kehulei= (String) request.getSession().getAttribute("kehulei"); if(kehulei!=null&&kehulei.length()>0) { params.put("kehulei", kehulei); } String kehutel= (String) request.getSession().getAttribute("kehutel"); if(kehutel!=null&&kehutel.length()>0) { params.put("kehutel", kehutel); } String kefuname= (String) request.getSession().getAttribute("kefuname"); if("客服".equals(relo)) { params.put("kefuname", names); }else { if(kefuname!=null&&kefuname.length()>0) { params.put("kefuname", kefuname); } } params.put("start", (pageNO-1)*40); params.put("pagesize",40); List all = khclientDao.like(params); pager.setData(all); pager.setIndex(pageNO); request.getSession().setAttribute("pageNO",pager.getIndex()); pager.setPageSize(40); pager.setTotal(khclientDao.getlikeTotal(params)); pager.setPath("like?"); request.setAttribute("pager", pager); return "client/cl-showlike"; }}
    3.4用户登录package com.controller;import java.util.*;import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest;import org.springframework.stereotype.Controller;import org.springframework.ui.ModelMap;import org.springframework.web.bind.annotation.RequestMapping;import com.dao.LogMapper;import com.dao.LogsMapper;import com.entity.Log;import com.util.Pagination;@Controller@RequestMapping("/log")public class LogController extends BaseController{ @Resource LogMapper logDao; @Resource LogsMapper logsDao; //登录信息显示 @RequestMapping("/show") public String show(Integer index,HttpServletRequest request,ModelMap model) { int pageNO = 1; if(index!=null){ pageNO = index; } Pagination pager = new Pagination(); Map params = new HashMap(); params.put("start", (pageNO-1)*40); params.put("pagesize", 40); List all = logDao.show(params); pager.setData(all); pager.setIndex(pageNO); request.getSession().setAttribute("pageNO", pager.getIndex()); pager.setPageSize(40); pager.setTotal(logDao.getTotal()); pager.setPath("show.do?"); request.setAttribute("pager", pager); return "dept/denlu/show"; } //登录信息模糊查找 @RequestMapping("/like") public String like(Integer index, Log data,HttpServletRequest request) { int pageNO = 1; if(index!=null){ pageNO = index; } Pagination pager = new Pagination(); Map params = new HashMap(); String lk=request.getParameter("lk"); String account=""; String onlineTime=""; String exitTime=""; if (lk!=null&&lk.length()>0) { request.getSession().setAttribute("account",data.getAccount()); request.getSession().setAttribute("onlineTime",data.getOnlineTime()); request.getSession().setAttribute("exitTime",data.getExitTime()); } account=(String) request.getSession().getAttribute("account"); onlineTime=(String) request.getSession().getAttribute("onlineTime"); exitTime=(String) request.getSession().getAttribute("exitTime"); if(account!=null&&account.length()>0) { params.put("account",account); } if(onlineTime!=null&&onlineTime.length()>0) { params.put("onlineTime",onlineTime); } if(exitTime!=null&&exitTime.length()>0) { params.put("exitTime",exitTime); } params.put("start", (pageNO-1)*40); params.put("pagesize", 40); List all = logDao.like(params); pager.setData(all); pager.setIndex(pageNO); request.getSession().setAttribute("pageNO", pager.getIndex()); pager.setPageSize(40); pager.setTotal(logDao.getlikeTotal(params)); pager.setPath("like.do?"); request.setAttribute("pager", pager); return "dept/denlu/show"; } //个人操作记录显示 @RequestMapping("/shows") public String shows(Integer index,HttpServletRequest request,ModelMap model) { int pageNO = 1; if(index!=null){ pageNO = index; } Pagination pager = new Pagination(); Map params = new HashMap(); params.put("start", (pageNO-1)*40); params.put("pagesize", 40); List all = logsDao.show(params); pager.setData(all); pager.setIndex(pageNO); request.getSession().setAttribute("pageNO", pager.getIndex()); pager.setPageSize(40); pager.setTotal(logsDao.getTotal()); pager.setPath("shows.do?"); request.setAttribute("pager", pager); return "dept/caozuo/show"; }}
    4.项目展示客户信息

    跟进信息

    登录信息

    权限管理
    0  留言 2021-09-01 15:21:35
  • 基于Jsp和Servlet实现的图书管理系统

    1.项目简介图书管理系统就是利用计算机,结合互联网对图书进行结构化、自动化管理的一种软件,来提高对图书的管理效率。本系统采用Java+Servlet+Jsp 的方式实现基于web的图书管理系统。
    1.1 开发工具及相关技术1.1.1 Java 技术Java 是由 Sun Microsystems 在 1995 年首先发布的编程语言和计算平台。有许多应用程序和 Web 站点只有在安装 Java 后才能正常工作,而且这样的应用程序和 Web 站点日益增多。Java 快速、安全、可靠。从笔记本电脑到数据中心,从游戏控制台到科学超级计算机,从手机到互联网,Java 无处不在。
    1.1.2 HTML、css、javascript技术HTML的英文全称是 Hypertext Marked Language,即超文本标记语言。HTML是由Web的发明者 Tim Berners-Lee和同事 Daniel W. Connolly于1990年创立的一种标记语言,它是标准通用化标记语言SGML的应用。用HTML编写的超文本文档称为HTML文档,它能独立于各种操作系统平台(如UNIX, Windows等)。使用HTML语言,将所需要表达的信息按某种规则写成HTML文件,通过专用的浏览器来识别,并将这些HTML文件“翻译”成可以识别的信息,即现在所见到的网页。
    层叠样式表(英文全称:Cascading Style Sheets)是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言。CSS不仅可以静态地修饰网页,还可以配合各种脚本语言动态地对网页各元素进行格式化。CSS 能够对网页中元素位置的排版进行像素级精确控制,支持几乎所有的字体字号样式,拥有对网页对象和模型样式编辑的能力。
    JavaScript(简称“JS”) 是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名的,但是它也被用到了很多非浏览器环境中,JavaScript 基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式和声明式(如函数式编程)风格。JavaScript在1995年由Netscape公司的Brendan Eich,在网景导航者浏览器上首次设计实现而成。因为Netscape与Sun合作,Netscape管理层希望它外观看起来像Java,因此取名为JavaScript。但实际上它的语法风格与Self及Scheme较为接近。JavaScript的标准是ECMAScript 。截至 2012 年,所有浏览器都完整的支持ECMAScript 5.1,旧版本的浏览器至少支持ECMAScript 3 标准。2015年6月17日,ECMA国际组织发布了ECMAScript 的第六版,该版本正式名称为 ECMAScript 2015,但通常被称为ECMAScript 6 或者ES6。
    1.1.3 Servlet技术Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。
    狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
    1.1.4 Eclipse开发工具Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。幸运的是,Eclipse 附带了一个标准的插件集,包括Java开发工具(Java Development Kit,JDK)。
    1.1.5 MySql数据库MySql是最流行的关系型数据库管理系统,在WEB应用方面MySQL是最好的RDBMS(Relational Database Management System:关系数据库管理系统)应用软件之一。MySql数据库有以下特点:

    Mysql是开源的,所以你不需要支付额外的费用。
    Mysql支持大型的数据库。可以处理拥有上千万条记录的大型数据库。
    MySQL使用标准的SQL数据语言形式。
    Mysql可以允许于多个系统上,并且支持多种语言。这些编程语言包括C、C++、Python、Java、Perl、PHP、Eiffel、Ruby和Tcl等。
    Mysql对PHP有很好的支持,PHP是目前最流行的Web开发语言。
    MySQL支持大型数据库,支持5000万条记录的数据仓库,32位系统表文件最大可支持4GB,64位系统支持最大的表文件为8TB。
    Mysql是可以定制的,采用了GPL协议,你可以修改源码来开发自己的Mysql系统。

    1.2系统功能描述系统的用户主要有两大类:一是图书管理系统的管理员,二是普通用户。根据用户类型的不同,将系统划分为普通用户端和管理员端,它们具有的主要功能如下:
    用户端


    图书查询:根据图书编号、图书名称查询图书信息,可查询图书的编号、名称、分类、作者、价格、在馆数量等。
    借阅信息:可查询图书的基本信息、借阅日期、截止还书日期、超期天数等。
    借阅历史:查询自己以往的借阅历史,包括哪些图书等具体信息。
    我的:查看个人资料,修改账户密码,退出系统。

    管理员端


    图书管理:根据图书编号、图书名称查询图书基本信息,添加、修改、删除图书。
    图书分类管理:根据分类名称查询图书分类信息,添加、修改、删除图书分类。
    图书借阅:展示所有正在借阅图书的信息。
    图书归还:展示所有已归还图书的信息。
    公告管理:向用户发布公告。
    读者管理:根据账号、姓名查询读者基本信息,添加、修改、删除读者信息。
    我的:查看个人资料,修改账户密码,退出系统。

    1.3工程结构及其说明
    项目名称:manage_books
    Package包说明:



    com.cya.util
    开发工具包,主要是对JDBC的封装




    com.cya.controller
    Servlet包,存放所有与前端交互的类


    com.cya.dao
    存放所有与数据库交互的类


    com.cya.pojo
    存放实体类



    2.数据库设计2.1表结构管理员表

    书本表

    分类表

    借阅历史表

    公告表

    2.2ER图
    3.主要功能详细设计与实现3.1用户端—图书查询模块用户访问图书查询模块时显示当前可以借阅图书,有按图书名称查询图书信息的功能,可以进行借书操作。

    其中查询功能的Servlet代码如下:
    package com.cya.controller;import java.io.IOException;import java.util.ArrayList;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.cya.dao.BookDao;import com.cya.pojo.Book;/** * Servlet implementation class selectServlet */@WebServlet("/selectServlet")public class selectServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public selectServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub //response.getWriter().append("Served at: ").append(request.getContextPath()); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub //doGet(request, response); request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); //因为在管理员界面和读者界面都有查找功能,为了将查找的结果返回正确的页面,设置了tip,tip=1表示管理员界面 int tip = Integer.parseInt(request.getParameter("tip")); String name = request.getParameter("name"); BookDao bookdao = new BookDao(); ArrayList<Book> data = bookdao.getLikeList(name); //将获取的结果存入请求中 request.setAttribute("data", data); String url = ""; //转发不同的界面 if (tip == 1) { url = response.encodeURL("/books/admin/admin_books.jsp"); } else { url = response.encodeURL("/books/user/select.jsp"); } //将请求转发 request.getRequestDispatcher(url).forward(request, response); }}
    3.2 用户端—借阅信息模块当普通用户借阅完图书,会在该模块自动生成借阅信息,如借阅日期,归还日期,也可在该模块进行还书,如下图所示。

    其中,还书功能的Servlet代码如下:
    package com.cya.controller;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import com.cya.pojo.Admin;import com.cya.dao.AdminDao;import com.cya.dao.BookDao;/** * Servlet implementation class borrowServlet */@WebServlet("/borrowServlet")public class borrowServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public borrowServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub //response.getWriter().append("Served at: ").append(request.getContextPath()); //设置编码类型 request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); BookDao bookdao = new BookDao(); //为了区分借书和还书的功能,设置tip,tip为1,表示借书 int tip = Integer.parseInt(request.getParameter("tip")); if (tip == 1) { //获取图书id int bid = Integer.parseInt(request.getParameter("bid")); HttpSession session = request.getSession(); Admin admin = new Admin(); String status=request.getParameter("status"); String id=""; if(status.equals("user")) { //获取到存入session的读者id id = (String) session.getAttribute("uid"); } else { //获取到存入session的aid读者id id = (String) session.getAttribute("aid"); } AdminDao admindao = new AdminDao(); //通过aid获取到读者的信息 admin = admindao.get_AidInfo2(id); //将借阅记录存入数据表 bookdao.borrowBook(bid, admin); response.sendRedirect("/manage_books/books/user/select.jsp"); } else { //还书功能,获取借阅记录的hid int hid = Integer.parseInt(request.getParameter("hid")); /** * 还书在管理员和读者界面都有,为了区分,设置了show字段,show为1表示读者界面 */ int show = Integer.parseInt(request.getParameter("show")); //调用还书函数,改变status字段 bookdao.borrowBook2(hid); if (show == 1) { response.sendRedirect("/manage_books/books/user/borrow.jsp"); } else { response.sendRedirect("/manage_books/books/admin/admin_borrows.jsp"); } } } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); }}
    3.3 管理员端—图书管理模块管理员可以通过根据图书号 、图书名称,作者名称,出版社等查询图书信息。

    管理员登录系统以后,可以进行图书添加操作,这是管理员主要的输入信息部分,填写好各项信息后,单击保存按钮,系统将对这些信息进行处理。界面见下图所示:
    除此以外,管理员对已经添加好的图书信息有修改权限。
    其中,添加图书功能的代码如下:
    package com.cya.controller;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.cya.dao.BookDao;/** * Servlet implementation class AddBookServlet */@WebServlet("/AddBookServlet")public class AddBookServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public AddBookServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub// response.getWriter().append("Served at: ").append(request.getContextPath()); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub// doGet(request, response); //设置编码类型 request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); //获取要添加图书的信息 String card = request.getParameter("card"); String name = request.getParameter("name"); String type = request.getParameter("type"); String autho = request.getParameter("autho"); String press = request.getParameter("press"); int num = Integer.parseInt(request.getParameter("num")); BookDao bookdao = new BookDao(); //调用函数,存入图书 bookdao.addBook(card, name, type, autho, press, num); response.sendRedirect("/manage_books/books/admin/admin_books.jsp"); }}
    3.4 管理员端—图书分类模块管理员在该界面可以增加、删除、修改图书分类信息,操作效果如图。

    修改图书分类功能的代码如下:
    package com.cya.controller;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.cya.dao.BookDao;import com.cya.dao.TypeDao;/** * Servlet implementation class updateBookTypeServlet */@WebServlet("/updateBookTypeServlet")public class updateBookTypeServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public updateBookTypeServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub// response.getWriter().append("Served at: ").append(request.getContextPath()); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub// doGet(request, response); //修改图书类型信息 request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); String name = request.getParameter("name"); int tid = Integer.parseInt(request.getParameter("tid")); TypeDao typedao = new TypeDao(); typedao.updateTypeBook(tid, name); response.sendRedirect("/manage_books/books/admin/admin_booksType.jsp"); }}
    0  留言 2021-09-01 15:19:15
  • 基于JS实现的贪吃蛇小游戏

    1、游戏描述贪吃蛇是一款非常经典的休闲类游戏。在一块固定大小的区域内,游戏玩家通过控制贪吃蛇的移动去吃食物,吃到食物后蛇身体变长。食物被蛇吃到后立马消失,并再次随机产生。蛇撞到四周墙壁或者自己身体时死亡。
    2、前期准备2.1 具备技能本游戏虽说是零基础,但你具备以下技能最佳:

    HTML(主要是div盒子模型,canvas画布)
    CSS(为你好看的游戏界面做准备)
    JavaScript(让小蛇动起来,逻辑代码实现)

    2.2 开发工具IDEA或者VSCode
    3、实现目标本篇文章欲带你实现以下功能:

    基本贪吃蛇(蛇的移动,吃食物,产生食物,增加分数)
    增加暂停游戏/继续游戏功能
    再来一局功能(贪吃蛇死亡后有再来一局提示)

    4、按键约定为方便玩家游戏,对操作按键做以下约定:

    上、下、左、右按键分别操作贪吃蛇的四个运动方向
    “+”、“-”按键分别控制贪吃蛇的加速、减速
    空格键控制游戏暂停/继续

    5、实现原理
    利用canvas画布完成运动场地、食物、贪吃蛇的展示
    利用数组存储贪吃蛇的坐标位置
    利用上、下、左、右键改变贪吃蛇的蛇头坐标
    不断重新绘制页面,给人造成贪吃蛇运动的错觉

    6、实现过程6.1 全局变量的定义与解释


    变量名称
    说明




    ROWS
    行数


    COLS
    列数


    CONTEXT
    canvas上下文对象


    BLOCK_SIZE
    贪吃蛇运动的格子大小


    snake[]
    保存蛇的坐标


    snakeCount
    蛇身长度


    foodX,foodY
    食物坐标


    interval
    计时


    moveTo
    蛇移动的方向


    isStop
    判断蛇是否暂停


    score
    玩家分数


    speed
    蛇运动速度



    6.2 方法的定义与解释


    方法名称
    参数
    返回值
    说明




    init()


    初始化方法


    start()


    游戏启动方法


    reLoad()


    页面重新加载方法


    keydown(keyCode)
    keyCode:按键的码值

    交互响应方法


    isDie()


    判断蛇是否死亡方法


    isEat()


    判断蛇是否吃到食物方法


    addSnake()


    增加蛇身方法


    addFood()


    增加食物方法


    move()


    蛇移动方法


    drawMap()


    绘制运动区域方法


    drawFood()


    绘制食物方法


    drawSnake()


    绘制蛇方法



    6.3 主要方法的代码实现初始化方法的实现
    function init() { ROWS = 35; //初始化行数 COLS = 25; //初始化列数 BLOCK_SIZE = 20; snakeCount = 3; moveTo = 2; score=0; document.getElementById("score").innerHTML=score; CONTEXT = document.getElementById('canvas').getContext('2d'); //初始化画布上下文对象的引用 for(var i = 0; i < snakeCount; i++) { snakes[i] = { x: i * BLOCK_SIZE, y: 0 }; } isStop=false; speed=500; addFood(); drawMap(); //初始化场地 drawSnake(); //初始化蛇 drawFood(); //初始化食物}
    绘制运动区域方法的实现
    function drawMap() { CONTEXT.clearRect(0, 0, BLOCK_SIZE * ROWS, BLOCK_SIZE * COLS); //画横线 for(var i = 0; i < COLS; i++) { CONTEXT.beginPath(); CONTEXT.moveTo(0, i * BLOCK_SIZE); CONTEXT.lineTo(BLOCK_SIZE * ROWS, i * BLOCK_SIZE); CONTEXT.strokeStyle = "gray"; CONTEXT.lineWidth=1; CONTEXT.stroke(); } //画竖线 for(var i = 0; i < ROWS; i++) { CONTEXT.beginPath(); CONTEXT.moveTo(i * BLOCK_SIZE, 0); CONTEXT.lineTo(i * BLOCK_SIZE, BLOCK_SIZE * COLS); CONTEXT.strokeStyle = "gray"; CONTEXT.lineWidth=1; CONTEXT.stroke(); }}
    判断蛇是否死亡方法的实现
    function isDie() { if(snakes[snakeCount - 1].x == -20 || snakes[snakeCount - 1].x == BLOCK_SIZE * ROWS || snakes[snakeCount - 1].y == -20 || snakes[snakeCount - 1].y == BLOCK_SIZE * COLS) { clearInterval(interval); document.getElementById("model2").style.display='block'; } for(var i = 0; i < snakeCount - 1; i++) { if(snakes[snakeCount - 1].x == snakes[i].x && snakes[snakeCount - 1].y == snakes[i].y) { clearInterval(interval); document.getElementById("model2").style.display='block'; } }}
    7、结果演示7.1 运行
    7.2 暂停
    7.3 死亡
    8、最后的话
    至此贪吃蛇已制作完成,谢谢你的支持
    本教程纯属个人思想构建,避免不了出现一些缺陷或错误,欢迎你批评指正
    0  留言 2021-08-31 15:02:08
  • 基于染色体遗传算法实现的排课系统

    1.项目简介借助本课题研究开发的基于java的自动排课系统,使学校教务管理人员可以随时掌握学校的排课情况,进一步指导学校的教学。
    本排课系统的主要功能大致包括:通过计算机可以进行排课管理,实现自动化排课,即无纸化排课,并且能了解、分析学校课程和教师资源的现状,能够充分的利用学校教室、教师等有限资源。考虑到在大学内课程变化较多,灵活性也较大,所以在功能设计上,我们将采取自动与手动相结合进行排课,以达到对课程的安排的相对合理性。
    智能排课系统的整体结构:整个系统分为B/S结构的教师与教务管理员登录功能、排课功能、课程管理功能、教室管理功能、教师管理功能、B/S结构的学生查课表功能与选课功能。

    登录模块:在C/S结构中,登入系统有对角色的分类与合法性的验证,并且根据不同的类型角色分配不同的权限;在B/S结构中,登入系统中只需要验证用户的合法性即可
    排课模块:包括手动排课、自动排课、查看全部课程信息、调整课程
    其他模块:主要是管理学生本人的信息、教师本人的信息、上课教室的信息、教学课程的信息、各个班级的信息等。大体是对这些信息进行增加、查找、修改、删除等操作

    1.1 研究目标
    掌握学校所有的课程和教师信息,包括教室,班级,上课老师及上课时间
    提供查询功能,可以查看某个班级所有课程信息
    可以对课程信息和教师信息进行查询和删除
    可以对课程进行手动排课和自动排课功能

    1.2 系统的要求用户界面要求友好、绚丽,操作方便。
    首先用户登录,登陆完毕后按权限显示功能列表,通过点击功能列表中某一功能,将相应功能页面打开,然后可以查看相应功能的详细信息,并对相关信息进行修改、删除等操作。
    系统应包含以下功能模块:

    系统管理:对用户的信息进行添加、修改等操作;对登录的用户进行登录限制;同时可以对系统的数据进行备份
    资源管理:包括课程管理、教师管理、专业管理、班级管理、教室管理等
    排课管理:能够按照排课算法的限定条件进行自动排课,生成课表;同时,对需要临时调整的课程、或者发生冲突的课程,能够进行手动调整
    输出管理:根据用户的权限、按照相应的需求,实现对班级、教师、教室的课表进行查询和打印

    1.3 排课系统对数据库设计的约束常用的硬约束条件有:

    所有的校方开出的课程都必须被安排
    除了可以合班上的课程以外,在同一时间内,同一个教室只能被一个班级使用
    除了选修课程以外,在同一时间内,一个班级只能安排一门课程
    在同一时间内,一个教师只能被安排在一个教室上一门课程
    同一个教师所上的所有不同的课程不能安排在同一时间上
    两个班的不同课程不能在同一个时间被安排在同一个教室
    教室的类型必须满足课程的要求
    教室的最大容纳人数必须大于安排在该教室上课的学生人数
    不同课程对时间段的不同要求,如体育课只能安排在白天上,选修课程只能安排在晚上上等

    常用的软约束条件有:

    同一班级的同一门课程的上课时间尽量间隔均匀些。例如,某班级的高等数学课在一周内需要安排俩次授课。两次授课时间的安排时间就需要尽量间隔一天或者一天以上
    每个班级在一周中的课程分布要均匀
    要尽量在较好的上课时间段安排课程
    对特定的课程、班级、教室、教师的单双周上课时间点尽量匹配,合理安排、节约教学资源

    1.4 系统技术架构1.4.1 前端
    vue 2.6
    vue-router 3.4
    vuex 3.5
    axios 0.19
    element-ui 2.13
    fullcalendar 5.3
    echarts 4.8

    1.4.2 后端
    SpringBoot 2.3
    MyBatis-Plus 3.3
    Swagger2 3.0
    poi 4.1

    2.数据库设计2.1 表结构教师表

    颜色表

    课程表

    排课表

    教师表

    2.2 创建表语句create table t_classroom( id bigint auto_increment primary key, name varchar(30) default '' not null comment '名称', enable_state int unsigned default 1 not null comment '停启用状态,1启用 2停用')comment '教室';create table t_color( id bigint auto_increment comment 'id' primary key, name varchar(30) default '' not null comment '名称', value char(7) default '' not null comment '值')comment '颜色';create table t_course( id bigint auto_increment comment 'id' primary key, name varchar(30) default '' not null comment '名称', enable_state int unsigned default 1 not null comment '停启用状态,1启用 2停用', duration int unsigned null comment '课程时长,单位分钟', background_color char(7) default '' not null comment '背景颜色')comment '课程';create table t_course_scheduling( id bigint auto_increment comment 'id' primary key, classroom_id bigint default 0 not null comment '教室id', course_id bigint default 0 not null comment '课程id', teacher_id bigint default 0 not null comment '教师id', date date null comment '日期', attend_time time null comment '上课时间', finish_time time null comment '下课时间')comment '排课';create table t_teacher( id bigint auto_increment comment 'id' primary key, name varchar(10) default '' not null comment '姓名', enable_state int unsigned default 1 not null comment '停启用状态,1启用 2停用')comment '教师';
    2.3 E-R图
    3.系统实现3.1 算法分析遗传算法采用类似基因演化的循环过程,其演算过程如下:

    针对待解决问题随机生成一组解,我们称之为种群(Population)。种群中的每个个体都是问题的解
    对个体适应度进行评估,如果个体的适应度符合优化准则,则输出最佳个体及其代表的最优解,并结束计算,否则转向第3步
    根据适应度对种群进行排序,从中挑选出最优的几个个体加入下一代种群,这一个过程也被称为精英选拔。新种群余下的部分通过对选拔出来的精英个体进行修改得到
    按照一定的交叉概率和交叉方法生成新的个体。交叉的做法是随机从最优种群中选取两个个体,以某个位置为交叉点合成一个新的个体



    按照一定的变异概率和变异方法生成新的个体。变异的做法是对种群做一个微小的、随机的改变。如果解的编码方式是二进制,那么就随机选取一个位置进行0和1的互相突变;如果解的编码方式是十进制,那么就随机选取一个位置进行随机加减


    由交叉和变异产生新一代的种群,然后返回第2步。如图所示

    以下是遗传算法的伪代码
    BEGIN: I=0; Initialize P(I); Fitness P(I); While(not Terminate-Condition) { I++; GA-Operation P(I); Fitness P(I); }END.
    染色体编码
    GA中首要考虑的是如何表现其问题,即如何对染色体编码,使之适用于GA操作。在经典的遗传算法中,常采用浮点数或二进制的编码方法,而研究中,每条染色体代表每一节课的安排,其结构表示如下:
    首先定义一个课程类,这个类包含了课程、班级、教师、教室、星期、周次几个属性。课程、班级、教师是安排好了的,教室、星期、周次是通过搜索算法来安排。

    每一条染色体表示一种可能的排课结果,至于排课结果的优劣,则由适应度函数评估染色体的适应值来决定。
    适应度函数
    遗传算法在进化中是以每个个体的适应度值为依据来选取下一代种群的。适应度函数设定的好坏直接影响到遗传算法的收敛速度和能否找到最优解。在本系统中,适应度函数的设计思想是对每条染色体中存在的冲突类型进行加权求和,其中权值Wi代表的是第i条规则的重要程度,若某条染色体违反了某条规则i,则将其值Pi置为1(若没有违反规则i,则Pi值为0),其受到的惩罚值为Wi*Pi 。染色体适应度函数值越小,则表示其拥有较好的授课时段和教室,其在下一代的演化中的生存概率就较大。
    在这次设计的适应性(schedule_cost)把Wi默认为1,具体如图所示:

    这个函数用来计算课表种群的冲突。当被测试课表冲突为0的时候,这个课表就是个符合规定的课表。冲突检测遵循下面几条规则:

    同一个教室在同一个时间只能有一门课
    同一个班级在同一个时间只能有一门课
    同一个教师在同一个时间只能有一门课

    初始化种群

    进化总框架

    交叉
    交叉是根据选择操作的结果,选取两条染色体作为父个体,再取一随机值random与系统预设的交叉率值(mutprob)比较,若 random < mutprob 则进行交换基因。

    变异
    变异是随机改变染色体中任一授课时段,将时段随机抽取一点在设定范围内改变。变异运算模仿了生物在自然遗传环境中由于各种偶然因素引起的基因突变,通过变异,染色体适应度有可能加强也有可能降低,但它确保了种群中遗传基因类型的多样性,使搜索能在尽可能大的空间中进行,获得最优解的可能性大大加强。

    3.2 工具类Jackson工具类
    public class JacksonUtils { private static final Logger log = LoggerFactory.getLogger(JacksonUtils.class); public final static Map<Class, JsonSerializer> SERIALIZER_MAP; public final static Map<Class, JsonDeserializer> DESERIALIZER_MAP; static { SERIALIZER_MAP = new LinkedHashMap<>(); SERIALIZER_MAP.put(Long.class, ToStringSerializer.instance); SERIALIZER_MAP.put(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(CommonConsts.TIME_FORMATTER))); SERIALIZER_MAP.put(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(CommonConsts.DATE_FORMATTER))); SERIALIZER_MAP.put(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(CommonConsts.DATETIME_FORMATTER))); DESERIALIZER_MAP = new LinkedHashMap<>(); DESERIALIZER_MAP.put(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(CommonConsts.TIME_FORMATTER))); DESERIALIZER_MAP.put(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(CommonConsts.DATE_FORMATTER))); DESERIALIZER_MAP.put(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(CommonConsts.DATETIME_FORMATTER))); } private final static ObjectMapper OBJECT_MAPPER; static { OBJECT_MAPPER = new ObjectMapper(); SimpleModule simpleModule = new SimpleModule(); SERIALIZER_MAP.forEach(simpleModule::addSerializer); DESERIALIZER_MAP.forEach(simpleModule::addDeserializer); OBJECT_MAPPER.registerModule(simpleModule); } /** * 对象转换字符串 * @param obj * @return */ public static String toStr(Object obj) { if (obj == null) { return null; } try { return OBJECT_MAPPER.writeValueAsString(obj); } catch (Exception e) { if (log.isDebugEnabled()) { log.debug("转换为字符串出错", e); } } return ""; } /** * 字符串转换对象 * @param str * @return */ public static Object toObj(String str) { return toObj(str, Object.class); } /** * 字符串转换指定类型 * @param str * @param clazz * @param <T> * @return */ public static <T> T toObj(String str, Class<T> clazz) { if (StringUtils.isEmpty(str) || clazz == null) { return null; } try { return OBJECT_MAPPER.readValue(str, clazz); } catch (Exception e) { if (log.isDebugEnabled()) { log.debug("转换为指定类型出错,str: {} class: {}", str, clazz, e); } } return null; } public static <T> T toObj(String str, TypeReference<T> typeReference) { if (StringUtils.isEmpty(str) || typeReference == null) { return null; } try { return OBJECT_MAPPER.readValue(str, typeReference); } catch (Exception e) { if (log.isDebugEnabled()) { log.debug("转换为指定范型出错,str: {}", str, e); } } return null; }}
    HTTP响应结果构建器
    public class ResponseEntityUtils { private static final String SERVER_ERROR = "服务器异常,请联系管理员。"; private static final Logger log = LoggerFactory.getLogger(ResponseEntityUtils.class); public static ResponseEntity<ApiResult<?>> ok(String msg) { return ResponseEntity.ok(new ApiResult<>(msg)); } public static <T> ResponseEntity<ApiResult<T>> ok(T data) { return ResponseEntity.ok(new ApiResult<>(data)); } public static ResponseEntity<ApiResult<?>> badRequest(String msg) { return new ResponseEntity<>(new ApiResult<>(msg), HttpStatus.BAD_REQUEST); } public static <T> ResponseEntity<ApiResult<?>> badRequest(Integer code, String msg, T data) { return new ResponseEntity<>(new ApiResult<>(code, msg, data), HttpStatus.BAD_REQUEST); } public static ResponseEntity<ApiResult<?>> unauthorized(String msg) { return new ResponseEntity<>(new ApiResult<>(msg), HttpStatus.UNAUTHORIZED); } public static ResponseEntity<ApiResult<?>> forbidden(String msg) { return new ResponseEntity<>(new ApiResult<>(msg), HttpStatus.FORBIDDEN); } public static ResponseEntity<ApiResult<?>> internalServerError(ErrorCodeEnum errorCodeEnum, Throwable throwable) { log.error(errorCodeEnum.getMsg(), throwable); return new ResponseEntity<>(new ApiResult<>(String.format("【%s】%s", errorCodeEnum.getCode(), SERVER_ERROR)), HttpStatus.INTERNAL_SERVER_ERROR); } public static ResponseEntity<ApiResult<?>> internalServerError(Integer code, String msg, Throwable throwable) { log.error(msg, throwable); return new ResponseEntity<>(new ApiResult<>(String.format("【%s】%s", code, SERVER_ERROR)), HttpStatus.INTERNAL_SERVER_ERROR); }}
    3.3 项目实现(主要功能)报表功能
    @Api(tags = "报表")@RequestMapping("report")@RestControllerpublic class ReportController extends BaseController { @Autowired private CourseSchedulingService courseSchedulingService; @ApiOperation(value = "老师上课数量", response = CourseSchedulingReportVO.class) @GetMapping("teacher/count") public ResponseEntity<ApiResult<List<CourseSchedulingReportVO>>> getReportTeacherCount(@RequestParam("startDate") String startDate, @RequestParam("endDate") String endDate) { return success(courseSchedulingService.getReportTeacherCount(startDate, endDate)); } @ApiOperation(value = "课程数量", response = CourseSchedulingReportVO.class) @GetMapping("course/count") public ResponseEntity<ApiResult<List<CourseSchedulingReportVO>>> getReportCourseCount(@RequestParam("startDate") String startDate, @RequestParam("endDate") String endDate) { return success(courseSchedulingService.getReportCourseCount(startDate, endDate)); }}
    3.4 排课算法实现@Overridepublic void batchSaveCourseScheduling(CourseSchedulingBatchSaveDTO saveDTO) { List<Integer> weekList = saveDTO.getWeekList(); LocalDate startDate = saveDTO.getStartDate(); LocalDate endDate = saveDTO.getEndDate(); List<LocalDate> dateList = new ArrayList<>(); while (startDate.compareTo(endDate) <= 0) { if (weekList.contains(startDate.getDayOfWeek().getValue())) { dateList.add(startDate); } startDate = startDate.plusDays(1); } List<CourseSchedulingListVO> voList = baseMapper.selectCourseSchedulingList(Wrappers.<CourseSchedulingDO>query() .eq("cs.classroom_id",saveDTO.getClassroomId()) .in("cs.date", dateList) .orderByAsc("cs.date, cs.attend_time")); Set<String> errorSet = new HashSet<>(); for (CourseSchedulingListVO vo : voList) { if (isTimeConflict(saveDTO.getAttendTime(), saveDTO.getFinishTime(), vo.getAttendTime(), vo.getFinishTime())) { errorSet.add(String.format("%s %s-%s %s %s %s", vo.getDate(), vo.getAttendTime(), vo.getFinishTime(), vo.getClassroomName(), vo.getCourseName(), vo.getTeacherName())); } } List<CourseSchedulingListVO> teacherVoList = baseMapper.selectCourseSchedulingList(Wrappers.<CourseSchedulingDO>query() .eq("cs.teacher_id", saveDTO.getTeacherId()) .in("cs.date", dateList) .orderByAsc("cs.date, cs.attend_time")); for (CourseSchedulingListVO vo : teacherVoList) { if (isTimeConflict(saveDTO.getAttendTime(), saveDTO.getFinishTime(), vo.getAttendTime(), vo.getFinishTime())) { errorSet.add(String.format("%s %s-%s %s %s %s", vo.getDate(), vo.getAttendTime(), vo.getFinishTime(), vo.getClassroomName(), vo.getCourseName(), vo.getTeacherName())); } } if (errorSet.size() > 0) { throw new BusinessException(ErrorCodeEnum.BUSINESS_COURSE_SCHEDULING_DATE_CONFLICT.getCode(), errorSet, "检测到排课时间冲突", null); } List<CourseSchedulingDO> doList = new ArrayList<>(); for (LocalDate date : dateList) { CourseSchedulingDO dataObj = AbstractCourseSchedulingConverter.INSTANCE.batchSaveDto2DO(saveDTO); dataObj.setDate(date); doList.add(dataObj); } saveBatch(doList);}
    4.展示4.1 排课


    4.2 导出

    4.3 报表统计
    5.项目部署5.1 环境
    docker 19.03
    docker-compose 1.26

    5.2 映射目录
    日志: ~/tams/logs
    数据库: ~/tams/mysql/data

    5.3 初始部署
    执行打包脚本 sh/package.sh
    执行打包文件中的安装脚本 install.sh
    访问地址

    首页 http://localhost:12010接口文档 http://localhost:12010/swagger-ui/

    5.4 升级
    执行要升级的数据库脚本
    执行打包文件中的升级脚本 upgrade.sh

    5.5 卸载
    执行打包文件中的卸载脚本 uninstall.sh
    0  留言 2021-08-31 14:54:14
  • 基于Jsp和MySQL的机票管理系统的设计

    1.项目简介近年来,我国发展迅速,对交通工具的需求量大幅度增加。飞机作为出行工具之一,花费时间短、用户体验度好,价格实惠、安全性高等优点自然成为人们的首选,这也导致等待时间长、购票效率低等一系列问题的出现,给用户和航空公司造成严重困扰。面对这些问题,在线机票预订系统显得格外重要。
    本系统使用Eclipse开发工具,使用Redis、MySQL数据库,采用MVC三层架构的方式,结合当前最流行的SSM框架以及支付宝沙箱支付环境来实现各个功能。系统分为用户端和管理员端。用户端实现了用户注册与登录、用户评论、机票查询,机票预订,订单查询、广告展示等功能。管理员端包括航班信息管理模块、订单信息管理模块、用户信息管理模块、留言评论管理模块、广告信息管理模块、个人信息管理模块等六大模块,具有开放体系结构的、易扩充的、易维护的、友好人机界面的优点。
    经过充分的测试,测试数据均正确无误,各个模块运行良好。机票预订系统的推出,为乘客出行提供方便,便于机场工作人员对机票信息进行管理,提高了机场工作人员对机票管理的工作效率。
    2.系统相关技术概述2.1 Java webJava Web是用Java技术来解决相关web互联网领域的技术总和。随着Web互联网技术的出现和推广,基于Java技术的Java Web技术应运而生,并为解决互联网相关问题提出解决方案。我们知道,Web是由服务器和客户端两方面组成。基于Java语言的Web框架有很多种,用以适用不同的技术需求,但是都遵循最基本的原则和技术路线,即采用了MVC的架构设计思想,并通过Servlet或者Filter进行请求拦截,同时使用约定,XML或Annotation来实现必备的相关配置,充分利用其面向对象的特质,实现前台用户请求和后台程序响应的工作流程。
    2.2 三大框架SSMSSM框架,是Spring + Spring MVC + MyBatis的缩写,这个是继SSH之后,目前比较主流的Java EE企业级框架,适用于搭建各种大型的企业级应用系统。
    Spring是一个开源框架,Spring是于2003年兴起的一个轻量级的Java开发框架,由Rod Johnson在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。简单来说,Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架。
    Spring MVC属于Spring Framework的后续产品,已经融合在Spring Web Flow里面,它原生支持的Spring特性,让开发变得非常简单规范。Spring MVC分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。
    MyBatis本是apache的一个开源项目IBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。MyBatis是一个基于Java的持久层框架。IBatis提供的持久层框架包括SQL Maps和Data Access Objects(DAO)MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的Pojo(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
    2.3 前端框架AngularJSAngularJS是一个开发动态Web应用的框架。它让你可以使用HTML作为模板语言并且可以通过扩展的HTML语法来使应用组件更加清晰和简洁。它的创新之处在于,通过数据绑定和依赖注入减少了大量代码,而这些都在浏览器端通过JavaScript实现。
    2.4 数据库MySQLMySQL是一种开放源代码的关系型数据库管理系统(RDBMS),使用最常用的数据库管理语言—结构化查询语言(SQL)进行数据库管理。MySQL是开放源代码的,因此任何人都可以在General Public License的许可下下载并根据个性化的需要对其进行修改。MySQL因为其速度、可靠性和适应性而备受关注。大多数人都认为在不需要事务化处理的情况下,MySQL是管理内容最好的选择。
    2.5 数据库RedisRedis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSIC语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。Redis和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set —有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,Redis支持各种不同方式的排序。另外,Redis为了保证效率,数据都是缓存在内存中,它会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
    2.6 开发工具EclipseEclipse是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。Eclipse附带了一个标准的插件集,包括Java开发工具(Java Development Kit,JDK)。
    3.需求分析3.1 系统实现目标如今,互联网遍布于生活的每个角落,不断改变着人们的生产生活,基于Web的机票预订系统就是借助互联网发展的热潮,方便大众,服务大众。具体实现以下两个目标:

    方便用户购票:用户可以访问前台系统浏览、查询航班信息,足不出户,预订机票,免去了以往寻找购票网点,排队购票的麻烦
    航空公司实现办公自动化:后台系统能使航空公司办事效率大幅度提高,它将所有的工作流程按照一系列流程进行规范化,从而减少工作时间,提高了人员的办事效率

    3.2 系统功能分析
    后台航班信息管理:主要是指添加航班信息,删除航班信息,查询航班信息和航班信息详细情况查看等
    后台订单信息管理:后台订单信息管理主要包括订单列表,查询订单信息,订单信息的删除等
    后台用户信息管理:主要指注册用户的展示与按条件查询注册用户
    后台留言评论管理:主要指展示用户的留言信息和按留言日期、留言用户查找留言信息等
    后台广告信息管理:主要指添加广告信息,删除广告信息,设置广告的有效性等
    后台个人信息管理:主要指查看个人信息,修改个人信息
    前台登录与注册管理:包括前台系统用户的注册与登录
    前台首页信息展示:主要是指航班信息展示、航班信息查询、航班信息详情、登录用户信息展示、留言板和个人信息详情与修改等
    前台订单页面:主要是订单内容的填写和订单详情。前台订单支付:是指使用支付宝沙箱环境支付订单

    3.3 系统用列图「系统前台功能用列图」

    「系统后台功能用列图」

    4.系统总体设计4.1 软件架构设计此项目使用经典的三层架构模式,分别是表现层,业务逻辑层和数据持久层。如下图所示。


    表现层:表现层也称为表示层,位于最外层(最上层),离用户最近。表现层用于显示数据和接收用户输入的数据,为用户提供一种交互式操作的界面
    业务逻辑层:业务逻辑层(Business Logic Layer)无疑是系统架构中体现核心价值的部分。它的关注点主要集中在业务规则的制定、业务流程的实现等与业务需求有关的系统设计,也即是说它是与系统所应对的领域(Domain)逻辑有关,很多时候,也将业务逻辑层称为领域层
    数据持久层」:数据持久层也称为是数据访问层,其功能主要是负责数据库的访问,可以访问数据库系统、二进制文件、文本文档或是XML文档。简单的说法就是实现对数据表的select、insert、update以及delete的操作

    4.2 总体功能模块设计本系统主要分为前台子系统和后台子系统,两个子系统包含的具体功能如下:

    前台功能

    用户登录用户注册航班查询机票详情机票预订订单支付订单查看用户留言个人信息查看与修改
    后台功能

    航班信息管理订单信息管理用户信息管理留言评论管理广告管理个人信息管理

    前台子系统和后台子系统详细功能如下图所示。

    4.2.1 前台系统功能设计用户登录功能,详细功能说明如表4.1所示

    用户注册功能,详细功能说明如表4.2所示

    航班查询功能,详细功能说明如表4.3所示

    机票详情功能,详细功能说明如表4.4所示

    机票预订功能,详细功能说明如表4.5所示

    订单支付功能,详细功能说明如表4.6所示

    订单查看功能,详细功能说明如表4.7所示

    用户留言功能,详细功能说明如表4.8所示

    个人信息查看与修改功能,详细功能说明如表4.9所示

    4.2.2 后台系统功能设计航班信息管理模块功能,详细功能说明如表4.10所示

    订单信息管理模块功能,详细功能说明如表4.11所示

    用户信息管理模块功能,详细功能说明如表4.12所示

    留言评论管理模块功能,详细功能说明如表4.13所示

    广告管理模块功能,详细功能说明如表4.14所示

    个人信息管理模块功能,详细功能说明如表4.15所示

    4.3 数据库设计4.3.1 数据库结构设计通过建立该系统各个模块的E-R图,使整个模块之间的功能变得更加清晰,模块间所具有的耦合性变的越低。管理员实体(Admin),留言评论实体(Discuss),航班实体(Flight),订单(Order)实体,普通用户实体(User)和广告信息实体(content)E-R图分别如下图所示。
    管理员实体(Admin)E-R图

    留言评论实体(Discuss)E-R图

    航班实体(Flight)E-R图

    订单实体(Order)E-R图

    普通用户实体(User)E-R图

    广告信息实体(Content)E-R图

    4.3.2 数据库表设计为实现数据库的设计,对数据进行分表处理,每一个表格代表不同的信息和功能,分别如下图所示。
    管理员信息表(admin),用于存放管理员信息,表结构如表4.16所示

    留言评论信息表(discuss),用于存放留言评论信息,表结构如表4.17所示

    航班信息表(flight),用于存放航班信息,表结构如表4.18所示

    订单信息表(order),用于存放订单信息,表结构如表4.19所示

    普通用户信息表(user),用于存放用户信息,表结构如表4.20所示

    5.系统详细设计及实现5.1 添加航班信息系统管理员登录后台系统后,点击侧边栏的航班信息管理按钮会出现下拉列表菜单,继续点击添加航班信息按钮可以进行添加航班信息操作。
    添加航班时输入航班号、起点、终点、始发机场、到达机场等信息,如下图所示。

    添加航班信息的过程:后台系统管理员进入添加航班信息页面后,填写航班号、起点、终点、始发机场、到达机场等相关信息后点击保存按钮,这是会随机生成flightId并与数据库中已经存在的flightId进行比较,保证航班Id唯一,之后继续判断输入的机票价格,航班座位数等数据是否有效,核对信息的有效性和完整性,最后存入数据库,具体流程如下图所示。

    主要代码
    @RequestMapping("addFlight") public Result addFlight(@RequestBody Flight flight ) { //设置日期格式 SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); // new Date()为获取当前系统时间 flight.setFlightId("F"+df.format(new Date())); try { flightManageService.addFlight(flight); return new Result(true,"添加成功"); } catch (Exception e) { e.printStackTrace(); return new Result(false,"添加失败"); }}
    5.2 航班信息列表系统管理员登录系统后有查看航班列表的权限,航班列表界面有添加航班,删除航班,搜索航班信息,航班信息详情,航班信息修改等功能,具体见下图,各个功能详细说明如表5.1所示。


    主要代码这里以航班查询功能service层代码为例
    public PageResult search(int pageNum, int pageSize, String searchEntity) { PageHelper.startPage(pageNum,pageSize); List<Flight> flightsList=flightManageMapper.select(searchEntity); Page<Flight> page=(Page<Flight>) flightsList; return new PageResult(page.getTotal(), page.getResult()); }
    5.3 订单信息列表订单信息列表是订单信息管理模块的一个子功能,展示的是前台所有用户的机票订单信息,如下图所示。
    系统管理员可以对订单进行查询,删除操作,各个功能详细说明如表5.2所示。


    主要代码这里以订单删除功能dao层的mapper代码为例
    <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" ><mapper namespace="com.cafuc.mapper.IOrderManageMapper"> <delete id="delete" parameterType="String"> delete from `order` where order_id in <foreach collection="selectIds" item="ids" open="(" close=")" separator=","> #{ids} </foreach> </delete></mapper>
    5.4 用户信息列表用户信息列表是用户信息管理模块的子功能,它是指把前台系统所有注册用户信息以列表的形式展示给后台系统管理员,方便系统管理员精确定位到每一个机票预订系统的使用者,对其进行管理,用户信息列表的界面如下图所示。
    系统管理员有查找系统使用用户和删除违反平台规定用户的权利,各个功能详细说明如表5.3所示。


    主要代码以用户搜索功能dao层的mapper代码为例
    <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" ><mapper namespace="com.cafuc.mapper.IUserManageMapper"> <select id="select" resultType="com.cafuc.pojo.User"> select DISTINCT * from `user` as u where u.user_name like concat('%',#{searchEntity},'%') </select></mapper>
    5.5添加广告信息广告作为网站的必要元素,在机票系统的前台页面也有广告展示的功能,后台增加了相应的管理模块,界面如下图所示。

    添加航班信息的过程如下:后台系统管理员进入添加航班信息页面后,填写航班号、起点、终点、始发机场、到达机场等相关信息后点击保存按钮,这是会随机生成flightId并与数据库中已经存在的flightId进行比较,保证航班Id唯一,之后继续判断输入的机票价格,航班座位数等数据是否有效,核对信息的有效性和完整性,最后存入数据库,具体流程如下图所示。

    主要代码以后台系统controller层ContentManageController.java类例
    @RequestMapping("addContent") public void addContent(@RequestParam("file") MultipartFile file,HttpServletRequest request,HttpServletResponse response) throws IOException { String describe=""; String url=""; String picture=""; if(request.getParameter("describe")!=null) { describe=request.getParameter("describe"); } if(request.getParameter("url")!=null) { url=request.getParameter("url"); } // 判断文件是否为空,空则返回失败页面 if (!file.isEmpty()) { try { // 获取文件存储路径(绝对路径) String path = request.getServletContext().getRealPath("/WEB-INF/file"); // 获取原文件名 String fileName = file.getOriginalFilename(); // 创建文件实例 File filePath = new File(path, fileName); // 如果文件目录不存在,创建目录 if (!filePath.getParentFile().exists()) { filePath.getParentFile().mkdirs(); System.out.println("创建目录" + filePath); } picture=filePath+""; // 写入文件 file.transferTo(filePath); Content content=new Content(); //设置日期格式 SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); // new Date()为获取当前系统时间 content.setContentId("C"+df.format(new Date())); content.setDescribe(describe); content.setPicture(picture); content.setUrl(url); contentManageServiceImpl.addContent(content); response.sendRedirect(request.getContextPath()+"/admin/list_content.html"); } catch (Exception e) { e.printStackTrace(); response.sendRedirect(request.getContextPath()+"/admin/add_content.html"); } } else { response.sendRedirect(request.getContextPath()+"/admin/add_content.html"); } }
    5.6 用户登录用户在进行机票预定,留言评论等功能时需要登录前台系统后才能进行,在浏览器地址栏输入 http://localhost:8081/flyTicket-portal-web/default/login.html 回车进入如下图所示界面。

    用户进行到登录界面,输入正确的用户名和密码就可以登录到前台系统,登录顺序图如下图所示。

    主要代码以controller层代码为例
    app.controller('portalLoginManageController',function($scope,$controller,portalLoginManageService){ $controller('baseController',{$scope:$scope}); //初始化 $scope.userEntity={userName:null,userPwd:null}; $scope.login=function(){ if($scope.userEntity.userName==null || $scope.userEntity.userName.trim()==""){ alert("用户名为空"); } else{ if($scope.userEntity.userPwd==null || $scope.userEntity.userPwd.trim()==""){ alert("密码为空"); } else{ portalLoginManageService.login($scope.userEntity).success(function(res){ if(res.result==false){ alert(res.message) } else{ window.location.href="index.html#?key="+$scope.userEntity.userName; } }); } }; }});
    5.7 航班信息展示在浏览器地址栏输入 http://localhost:8081/flyTicket-portal-web/default/index.html 出现如下图所示界面,首页面展示所有航班信息。每一条信息包含出发城市、到达城市、出发机场、到达机场,出发时间、到达时间、机票价格等信息。

    5.8 航班信息查询用户可以通过航班查询功能精确查找到所需信息,节省时间简化操作。通过输入航班类型、出发时间、出发城市、到达城市等搜索条件实现航班查询。如下图以成都为到达城市为例,搜索结果如下图所示。

    代码以dao层PortalManageMapper.xml为例
    <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" ><mapper namespace="com.cafuc.mapper.IPortalManageMapper"> <select id="select" resultType="com.cafuc.pojo.Flight"> select * from flight as f <where> <if test="flightStartTime1 !=null and flightStartTime1 !=''"> and f.flight_start_time like concat('%',#{flightStartTime1},'%') </if> <if test="flightStartPlace !=null and flightStartPlace !=''"> and f.flight_start_place like concat('%',#{flightStartPlace},'%') </if> <if test="flightEndPlace !=null and flightEndPlace !=''"> and f.flight_end_place like concat('%',#{flightEndPlace},'%') </if> </where> </select></mapper>
    5.9 留言板点击前台系统右上角“留言板”按钮进入都留言页面如下图所示。
    留言评论是前台系统使用者完成注册后具有的功能,用户可以通过留言评论功能对所购班次机票进行全方位的评价,也可以对其在使用过程中遇到的问题进行反馈。

    主要代码以前台系统controller层DiscussManageController.java类例
    @RestController@RequestMapping("discussManage")public class DiscussManageController { @Resource private IDiscussManageService discussManageService; @RequestMapping("addDiscuss") public Result addDiscuss(@RequestBody Discuss discuss){ try { System.out.println(discuss); discussManageService.addDiscuss(discuss); return new Result(true, "评论成功"); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); return new Result(false, "评论失败"); } } @RequestMapping("init") public List<Discuss> init(){ return discussManageService.init(); }}
    5.10 订单支付机票预订系统的订单支付功能使用的是支付宝沙箱环境支付,蚂蚁沙箱环境 (Beta) 是协助开发者进行接口功能开发及主要功能联调的辅助环境。
    登录支付宝沙箱平台依次完成生成买家和卖家账号信息、生成RSA秘钥、设置公钥信息、设置应用网关等应用环境配置,完成配置后下载官方测试代码。
    本系统选择的是电脑应用java版本,将下载的项目导入到eclipse工作空间,设置核心配置文件信息,打开flyTicket-portal-web项目下com.alipay.config包中的AlipayConfig.java文件配置如下信息:
    //沙箱APPIDpublic static final String app_id = "**这里需要自己申请**";//沙箱私钥public static final String merchant_private_key = "**这里需要自己申请**";//支付宝公钥public static final String alipay_public_key = "**这里需要自己申请**";//沙箱网关地址public static final String gatewayUrl = "https://openapi.alipaydev.com/gateway.do";//服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问public static String notify_url = "http://localhost:8081/flyTicket-portal-web/pay/notify_url.jsp";//页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问public static String return_url = "http://localhost:8081/flyTicket-portal-web/orderManage/complete";
    完成以上配置后就可以实现订单支付功能了,点击确认付款后跳转到如下图所示界面。

    点击付款按钮后如下图所示,可以登录账户付款,也可以使用手机端沙箱支付宝完成付款。

    完成付款后如下图所示

    主要代码如下
    //支付完成后@RequestMapping("complete")public void complete(HttpServletRequest request,HttpServletResponse response) throws IOException { System.out.println(request.getSession().getAttribute("order")); Order order=(Order)request.getSession().getAttribute("order"); try { //将数据插入到订单表中 orderManageService.insertOrder(order); //更改库存 Flight flight=orderManageService.findOneByFlightNumber(order.getFlightNumber()); if(order.getGrade().equals("f")) { flight.setFlightHighNumber(flight.getFlightHighNumber()-1); } else if(order.getGrade().equals("b")) { flight.setFlightMiddleNumber(flight.getFlightMiddleNumber()-1); } else { flight.setFlightBaseNumber(flight.getFlightBaseNumber()-1); } orderManageService.updatesNum(flight); } catch (Exception e) { e.printStackTrace(); } response.sendRedirect(request.getContextPath()+"/default/index.html"); }
    1  留言 2021-08-31 14:41:09
  • 基于Springboot+Vue+ElementUI实现的智能家居后台管理系统

    1.项目简介1.1 背景分析本项目是基于上一篇文章【基于Springboot+Layui实现的智能家居门户系统】续写的,主要是详细介绍智能家居门户系统的后台管理部分,管理员可以通过本项目的功能系统快速管理前台页面和功能。
    1.2 技术栈采用的技术栈是前后端分离机制,前端采用的是Vue+ElementUI搭建的,后端在原本的项目上进行改写,采用Mybatis-plus逆向工程代码生成器快速生成架构和基础代码,同时引入himrbate持久层jpa框架,减少了sql的编写工作量。
    2.数据库设计2.1 表结构前台导航栏表

    新闻分类表

    产品专利表

    产品分类表

    用户表

    权限菜单表

    2.2 E-R图
    3.项目实现3.1 认证功能实现@PostMapping("/login")public ResponseBo login(@RequestBody User user) { Session session = super.getSession(); String sessionCode = (String) session.getAttribute(CODE_KEY); System.out.println(sessionCode); user.setLoginPassword(MD5Utils.encrypt(user.getLoginPassword())); UsernamePasswordToken token = new UsernamePasswordToken(user.getLoginAccount(), user.getLoginPassword()); try { Subject subject = getSubject(); if (subject != null) { subject.logout(); } super.login(token); Subject subject1 = getSubject(); subject1.getSession().setTimeout(86400000); return ResponseBo.ok(this.userService.selectOne(new EntityWrapper<User>().eq("login_account", token.getUsername()))); } catch (UnknownAccountException | IncorrectCredentialsException | LockedAccountException e) { return ResponseBo.error(e.getMessage()); } catch (AuthenticationException e) { return ResponseBo.error("认证失败!"); }}@GetMapping("/loginOut")public ResponseBo loginOut() { Subject subject = getSubject(); if (subject != null) { subject.logout(); return ResponseBo.ok("成功退出"); } return ResponseBo.ok("尚未登录");}@GetMapping("/getUser")public ResponseBo getUser(@RequestParam("userId") Integer userId) { try { User user = this.userService.show(userId); return ResponseBo.ok(user); } catch (Exception e) { return ResponseBo.error("获取用户失败,请联系网站管理员!"); }}@GetMapping("/getList")public ResponseList<User> getUserList(@RequestParam(value = "page", defaultValue = "1") Integer page, @RequestParam(value = "rows", defaultValue = "10") Integer rows) { return userService.list(page, rows);}@PostMapping("/deleteUser")public ResponseBo delete(@RequestBody Integer[] ids) { try { userService.delete(ids); return ResponseBo.ok(); } catch (Exception e) { return ResponseBo.error("删除用户失败,请联系网站管理员!"); }}@PostMapping("/saveUser")public ResponseBo saveUser(@RequestBody User user) { if (StringUtils.isEmpty(user.getLoginAccount())) { return ResponseBo.warn("请输入登录账号名!"); } if (user.getId() == null) { try { if (userService.findUserByAccount(user.getLoginAccount()) != null) { return ResponseBo.warn("该用户名已被使用!"); } user.setLoginPassword(MD5Utils.encrypt(user.getLoginAccount(), user.getLoginPassword())); userService.add(user); return ResponseBo.ok(); } catch (Exception e) { return ResponseBo.error(e.getMessage()); } } else { try { User u = userService.show(user.getId()); if (u.getLoginPassword().equals(user.getLoginPassword()) && u.getLoginAccount().equals(user.getLoginAccount())) { userService.update(user); } else { user.setLoginPassword(MD5Utils.encrypt(user.getLoginAccount(), user.getLoginPassword())); userService.update(user); } return ResponseBo.ok(); } catch (Exception e) { return ResponseBo.error(e.getMessage()); } }
    3.2 全局异常拦截器@ControllerAdvicepublic class GlobalExceptionHandler { private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); @ExceptionHandler(value = RuntimeException.class) public ModelAndView MyExceptionErrorHandler(RuntimeException ex) { ModelAndView m = new ModelAndView(); logger.error("MyExceptionErrorHandler info:{}", ex.getMessage()); m.setViewName("error/404"); return m; }
    3.3 跨域配置// The Vue build version to load with the `import` command// (runtime-only or standalone) has been set in webpack.base.conf with an alias.import Vue from 'vue'import App from './App'import ElementUI from 'element-ui'import Axios from 'axios'import 'element-ui/lib/theme-chalk/index.css'import router from './router'Vue.config.productionTip = false;Axios.interceptors.response.use(function (response) { return response},function (error) { router.replace({path:'/login',query:{redirect:router.currentRoute.fullPath}}); if (error.response.status === 302){ localStorage.clear(); router.replace({path:'/login',query:{redirect:router.currentRoute.fullPath}}); } else if(error.response.status === 403){ ElementUI.Notification.error({ title:'无权访问', message:'您无权访问该资源!' }); return error; }else { ElementUI.Notification.error({ title:'请求错误', message:'Network Error' }); return error; }});router.beforeEach((to, from, next) => { window.document.title = to.meta.title ? to.meta.title + '-' + '网站后台' :'恭逸科技有限公司后台管理系统'; // if (!sessionStorage.getItem(Config.tokenKey) && to.path != '/login') { // next({path: '/login'}); // } else { next(); // }});router.afterEach(transition => {});// http request 请求拦截器,有token值则配置上token值Vue.use(ElementUI);/* eslint-disable no-new */new Vue({ el: '#app', router, components: { App }, template: '<App/>'});
    module.exports = { dev: { // Paths assetsSubDirectory: 'static', assetsPublicPath: '/', proxyTable: { '/':{ target: 'http://localhost:8080/', changeOrigin: true, pathRewrite: { '^/': '/' } } }, // Various Dev Server settings host: 'localhost', // can be overwritten by process.env.HOST port: 80, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined autoOpenBrowser: false, errorOverlay: true, notifyOnErrors: true, poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- /** * Source Maps */ // https://webpack.js.org/configuration/devtool/#development devtool: 'cheap-module-eval-source-map', // If you have problems debugging vue-files in devtools, // set this to false - it *may* help // https://vue-loader.vuejs.org/en/options.html#cachebusting cacheBusting: true, cssSourceMap: true }, build: { // Template for index.html index: path.resolve(__dirname, '../dist/index.html'), // Paths assetsRoot: path.resolve(__dirname, '../dist'), assetsSubDirectory: 'static', assetsPublicPath: './', /** * Source Maps */ productionSourceMap: true, // https://webpack.js.org/configuration/devtool/#production devtool: '#source-map', // Gzip off by default as many popular static hosts such as // Surge or Netlify already gzip all static assets for you. // Before setting to `true`, make sure to: // npm install --save-dev compression-webpack-plugin productionGzip: false, productionGzipExtensions: ['js', 'css'], // Run the build command with an extra argument to // View the bundle analyzer report after build finishes: // `npm run build --report` // Set to `true` or `false` to always turn it on or off bundleAnalyzerReport: process.env.npm_config_report }}
    3.4 前端运行环境配置'use strict'const merge = require('webpack-merge')const prodEnv = require('./prod.env')module.exports = merge(prodEnv, { NODE_ENV: '"development"'})
    4.项目展示登录页

    首页

    新闻管理

    修改新闻

    新闻分类管理

    产品管理

    功能分类

    公司信息管理

    专利证书管理

    审核在线留言

    栏目管理

    图片管理

    用户管理

    菜单权限管理

    热门词管理

    修改密码

    5.总结到此为止,本项目已经算是告一段落了,这个项目是我本人第一次接取外包项目来做,做出来的项目也算比较完善的一个了,在这其中花费了很多时间去了解这么一个的网站的数据库和架构怎么去搭建,也遇到很多困难,比如项目上线后多用户访问,服务器会承受较大压力,所以在后期如果有机会或者是有时间的话我会对其进行完善,引入微服务或者搭建负载均衡去缓解这个问题,同时,在一起学习的过程中,如果大家有什么好的建议也可以提出来,我有空看到会及时回复,希望大家踊跃发言!!!
    0  留言 2021-08-28 09:39:55
显示 0 到 25 ,共 25 条
eject