# App管理平台 **Repository Path**: fudaosheng/appguanlipingtai ## Basic Information - **Project Name**: App管理平台 - **Description**: 大二下SSM结课设计,包含两个子系统,app开发者平台和后台管理平台。app开发者平台主要功能:app相关的发布维护,app信息修改。后台管理平台:app的审核,app开发者账号审核。内有超详细项目文档 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 1 - **Created**: 2020-06-13 - **Last Updated**: 2022-05-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### **App管理平台** 介绍 大二下SSM结课设计,包含两个子系统,app开发者平台和后台管理平台。app开发者平台主要功能:app相关的发布维护,app信息修改。后台管理平台:app的审核,app开发者账号审核。内有超详细项目文档 #### 软件架构 软件架构说明 #### 安装教程 1. MyEclipse10 2. mysql5.5 3. tomcat7 ### **系统需求分析与总体设计** **1.项目需求分析:** 本项目的目的是为了方便app开发者,和app管理者方便,直观的对app版本,状态,下载量等进行管理。因此必须根据app开发者,和app管理者的权限不同设计两套不同权限的子系统。 **1.1 app开发平台:** 让开发者入驻自行操作,例如上传自己开发的app,进行版本的更新维护等。 1.2 app管理平台: 主要负责后台数据的维护和管理。后台管理系统的超级管理员就只需要做一些app开发平台上传数据的审核工作即可,如APP审核、开发者账号的审核等。 优点:app信息上传维护与后台管理信息分开,降低了后台管理人员的任务量,并方便了开发人员的及时维护与发布app。 ** 2.项目技术架构** 本系统采用Spring MVC+Spring+MyBatis集成框架来开发。以Spring作为系统核心框架,数据持久化使用MyBatis完成,表现层使用Spring MVC。通过这些复习加深本学期学习的框架,三个框架的组合可以保证更高的开发效率。 **3.项目数据库设计** 3.1登录表设计: 首先系统拥有两种角色的用户(超级管理员和开发者),分别对应不同的子系统。基于架构角度和系统安全性的考虑,采用两张用户表(开发者用户表dev_ user 和后台用户表backend_ user) 来进行数据的维护记录,以便于系统的迁移以及功能的扩展。 **开发者用户表** :dev_user: 字段说明: Id 主键,并且为了app开发着申请账号设置成了auto_increment ****后台管理员表:** backend_user** ** 3.2 app信息表设计:** App信息表(app_ info) 和APP版本信息表(app_ version) 来记录APP的相关信息。由于开发者开发出一套APP应用可以发布多个版本,所以APP基础信息表与APP版本信息表之 间是一对多的关系。APP基础信息表和APP版本信息表中的一些描述字段,如所属 平台、APP状态、发布状态等均来自数据字典表( data_ dictionary), APP 所属分类则 来自分类表(app. _category)。 **2使用技术** (1)使用Mybatis操作数据库,增删查改 (2)使用spring配置数据库信息,管理业务bean (3)使用spring、mybatis、springMVC整合 (4)使用前端框架Bootstrap进行响应式前端页面开发 (5)使用Git进行项目版本控制 (6)使用ajax进行异步验证 (7)使用Json进行前后端数据传递 ### ### 本项目的持久层(mybatis)设计 **1. Mybatis配置文件设计:** ``` ``` **2. 数据库映射类设计:** 数据库映射类设计注意点:(1)为了保证对数据库操作的正确性必须保证对应的映射类属性名和数据表的字段名相同,并且类型匹配。如dev_user中loginname的类型为char,那么在其映射类中对应属性loginname的类型必须为String。 (2) 映射类对应的属性必须设置相对应的get,set方法。 **3.Mapper映射文件设计** 根据实际的操作,如修改app信息,删除app信息等进行mybatis映射文件配置 ,并且mapper标签的namespace属性值为对应的映射接口路径。 Mybatis映射文件注意点: (1)xml中某些特殊符号作为内容信息时需要做转义,否则会对文件的合法性和使用造成影响 (2) sql内容 test里面的判断字符串相等时需要使用双引号"",如果使用单引号 则无法识别标签中的内容 (3)多表联合查询时如果需要自定义返回类型要用resultMap **4. Mapper接口设计** Mapper接口路径必须与相对于的Mapper xml文件指定路经相同,并且里面的抽象方法名,参数,返回类型都必须与相对于XML文件方法名,返回值,参数相同。 **5.在MapperScannerConfigurer中指定Mapper接口路径** ``` ``` ### spring +springmvc+mybatis整合设计 ### 1. 准备工作 在项目resources中引入相关的配置文件,如database.properties,注意修改其对应的数据库名,引入log4j.properties文件 ### 2. 编写spring配置文件 2.1引入spring文件配置头 ``` (1) ``` 2.2设置注解扫描路径 ``` (13) (14) ``` 2.3JNDI数据源连接数据库 ``` (15) (16) (18) (19) (20) (21) (22) (23) (24) (25) (26) (27) (28) (29) (30) (31) (32) (33) (34) (35) (36) (37) ``` 2.3配置事务管理 ``` (38) (39) (40) (41) (42) ``` 2.4配置SqlSessionFactoryBean ``` (43) (44) (45) (46) (47) ``` 2.5配置spring切面编程 ``` (48) (49) (50) (51) (52) (53) (54) (55) (56) (57) (58) (59) ``` 2.6设置Mapper接口扫描路径 ``` (60) (61) (62) (63) ``` ### 3. 配置springMVC文件 3.1指定Controller路径 3.2配置: ``` application/json;charset=UTF-8 text/html;charset=UTF-8 application/json WriteDateUseDateFormat ``` 3.3配置静态资源管理器 3.4配置多视图解析器 ``` ``` 3.5配置拦截器 ``` ``` 3.6配置文件管理器 ``` ``` ### 4. 配置web.xml文件 4.1配置spring配置文件路径 ``` contextConfigLocation classpath:applicationContext-*.xml ``` 4.2spring过滤器 ``` encodingFilter org.springframework.web.filter.CharacterEncodingFilter encoding UTF-8 forceEncoding true encodingFilter /* ``` 4.3配置springMVC ``` spring org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:springmvc-servlet.xml 1 spring / org.springframework.web.context.ContextLoaderListener ``` 4.4log4j配置 ``` log4jConfigLocation classpath:log4j.properties ``` ``` webAppRootKey SMBMMVC.root ``` 4.5配置监听器 ``` org.springframework.web.util.Log4jConfigListener ``` ### 5.根据spring,springMVC配置文件中指定的控制器路径,业务类路径编写控制器,业务类及其实现类 ### 开发者管理平台设计 需求: ![输入图片说明](https://images.gitee.com/uploads/images/2020/0613/201124_2643b997_7602838.png "屏幕截图.png") 1. 登录: ``` user = devUserService.login(devCode,devPassword); session.setAttribute(Constants.DEV_USER_SESSION, user); ``` 2. 退出: //清除session ``` session.removeAttribute(Constants.DEV_USER_SESSION); return "devlogin"; ``` **3. 查看app信息(动态sql,翻页)** 3.1动态sql:if+trim ``` ``` 3.2翻页,主要是利用limit进行限制查询。 当前页码:通过点击上下页发送url请求并参入一个参数(该参数可为空),如果不为空时该参数即为当前页数(为空时初始值设为1) 页面容量:根据页面容量设置一个整数值。 总记录数:select *from dev_user返回的list的list.size()的值 总页码: If(总记录数%页面容量==0){ 总页码=总记录数/页面容量 } Else{ 总页码=Math.floor(总记录数/页面容量)+1 } **4. 修改app信息** ``` update app_info softwareName=#{softwareName}, supportROM=#{supportROM}, interfaceLanguage=#{interfaceLanguage}, updateDate=#{updateDate}, softwareSize=#{softwareSize}, appInfo=#{appInfo}, status=#{status}, onSaleDate=#{onSaleDate}, offSaleDate=#{offSaleDate}, categoryLevel1=#{categoryLevel1}, categoryLevel2=#{categoryLevel2}, categoryLevel3=#{categoryLevel3}, downloads=#{downloads}, flatformId=#{flatformId}, logoPicPath=#{logoPicPath}, logoLocPath=#{logoLocPath}, modifyBy=#{modifyBy}, modifyDate=#{modifyDate}, ``` **5. 删除app信息:根据点击删除按钮时url带的id值删除指定信息** ``` delete from app_info where id = #{id} ``` **6. 修改版本信息** ``` . update app_info set versionId=#{versionId} where id = #{id} ``` **8. App上下架** 根据app_info中status的值,判断上下架状态 ``` 上架 下架 ``` ** ### ### 后台管理平台设计 ** 需求: ![输入图片说明](https://images.gitee.com/uploads/images/2020/0613/201237_a6ef71ff_7602838.png "屏幕截图.png") 1. 登陆: ``` @RequestMapping(value="/dologin",method=RequestMethod.POST) public String doLogin(@RequestParam String userCode,@RequestParam String userPassword,HttpServletRequest request,HttpSession session){ logger.debug("doLogin===================================="); //调用service方法,进行用户匹配 BackendUser user = null; try { user = backendUserService.login(userCode,userPassword); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } if(null != user){//登录成功 //放入session session.setAttribute(Constants.USER_SESSION, user); //页面跳转(main.jsp) return "redirect:/manager/backend/main"; }else{ //页面跳转(login.jsp)带出提示信息--转发 request.setAttribute("error", "用户名或密码不正确"); return "backendlogin"; } } ``` 2. 退出 ``` @RequestMapping(value="/logout") public String logout(HttpSession session){ //清除session session.removeAttribute(Constants.USER_SESSION); return "backendlogin"; } ``` **3. 待审核列表** ``` @RequestMapping(value="/list") public String getAppInfoList(Model model,HttpSession session, @RequestParam(value="querySoftwareName",required=false) String querySoftwareName, @RequestParam(value="queryCategoryLevel1",required=false) String _queryCategoryLevel1, @RequestParam(value="queryCategoryLevel2",required=false) String _queryCategoryLevel2, @RequestParam(value="queryCategoryLevel3",required=false) String _queryCategoryLevel3, @RequestParam(value="queryFlatformId",required=false) String _queryFlatformId, @RequestParam(value="pageIndex",required=false) String pageIndex){ logger.info("getAppInfoList -- > querySoftwareName: " + querySoftwareName); logger.info("getAppInfoList -- > queryCategoryLevel1: " + _queryCategoryLevel1); logger.info("getAppInfoList -- > queryCategoryLevel2: " + _queryCategoryLevel2); logger.info("getAppInfoList -- > queryCategoryLevel3: " + _queryCategoryLevel3); logger.info("getAppInfoList -- > queryFlatformId: " + _queryFlatformId); logger.info("getAppInfoList -- > pageIndex: " + pageIndex); List appInfoList = null; List flatFormList = null; List categoryLevel1List = null;//列出一级分类列表,注:二级和三级分类列表通过异步ajax获取 List categoryLevel2List = null; List categoryLevel3List = null; //页面容量 int pageSize = Constants.pageSize; //当前页码 Integer currentPageNo = 1; if(pageIndex != null){ try{ currentPageNo = Integer.valueOf(pageIndex); }catch (NumberFormatException e) { // TODO: handle exception e.printStackTrace(); } } Integer queryCategoryLevel1 = null; if(_queryCategoryLevel1 != null && !_queryCategoryLevel1.equals("")){ queryCategoryLevel1 = Integer.parseInt(_queryCategoryLevel1); } Integer queryCategoryLevel2 = null; if(_queryCategoryLevel2 != null && !_queryCategoryLevel2.equals("")){ queryCategoryLevel2 = Integer.parseInt(_queryCategoryLevel2); } Integer queryCategoryLevel3 = null; if(_queryCategoryLevel3 != null && !_queryCategoryLevel3.equals("")){ queryCategoryLevel3 = Integer.parseInt(_queryCategoryLevel3); } Integer queryFlatformId = null; if(_queryFlatformId != null && !_queryFlatformId.equals("")){ queryFlatformId = Integer.parseInt(_queryFlatformId); } //总数量(表) int totalCount = 0; try { totalCount = appService.getAppInfoCount(querySoftwareName, queryCategoryLevel1, queryCategoryLevel2, queryCategoryLevel3, queryFlatformId); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } //总页数 PageSupport pages = new PageSupport(); pages.setCurrentPageNo(currentPageNo); pages.setPageSize(pageSize); pages.setTotalCount(totalCount); int totalPageCount = pages.getTotalPageCount(); //控制首页和尾页 if(currentPageNo < 1){ currentPageNo = 1; }else if(currentPageNo > totalPageCount){ currentPageNo = totalPageCount; } try { appInfoList = appService.getAppInfoList(querySoftwareName, queryCategoryLevel1, queryCategoryLevel2, queryCategoryLevel3, queryFlatformId, currentPageNo, pageSize); flatFormList = this.getDataDictionaryList("APP_FLATFORM"); categoryLevel1List = appCategoryService.getAppCategoryListByParentId(null); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } model.addAttribute("appInfoList", appInfoList); model.addAttribute("flatFormList", flatFormList); model.addAttribute("categoryLevel1List", categoryLevel1List); model.addAttribute("pages", pages); model.addAttribute("querySoftwareName", querySoftwareName); model.addAttribute("queryCategoryLevel1", queryCategoryLevel1); model.addAttribute("queryCategoryLevel2", queryCategoryLevel2); model.addAttribute("queryCategoryLevel3", queryCategoryLevel3); model.addAttribute("queryFlatformId", queryFlatformId); //二级分类列表和三级分类列表---回显 if(queryCategoryLevel2 != null && !queryCategoryLevel2.equals("")){ categoryLevel2List = getCategoryList(queryCategoryLevel1.toString()); model.addAttribute("categoryLevel2List", categoryLevel2List); } if(queryCategoryLevel3 != null && !queryCategoryLevel3.equals("")){ categoryLevel3List = getCategoryList(queryCategoryLevel2.toString()); model.addAttribute("categoryLevel3List", categoryLevel3List); } return "backend/applist"; } **4. 审核app** @RequestMapping(value="/checksave",method=RequestMethod.POST) public String checkSave(AppInfo appInfo){ logger.debug("appInfo =========== > " + appInfo.getStatus()); try { if(appService.updateSatus(appInfo.getStatus(),appInfo.getId())){ return "redirect:/manager/backend/app/list"; } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return "backend/appcheck"; } ``` 审核成功则修改app_info中status字段 **5. Session拦截** ``` @RequestMapping(value="/backend/main") public String main(HttpSession session){ if(session.getAttribute(Constants.USER_SESSION) == null){ return "redirect:/manager/login"; } return "backend/main"; ``` } #### 码云特技 1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md 2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com) 3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目 4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目 5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) 6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)