基于springboot+layui+Shiro实现的校园二手市场后台管理系统
1.项目介绍
随着人们生活水平的普遍提高,学生各种消耗品升级换代更新加快,,面临着大量物品的处置问题。课本,电脑、自行车、等都成为了较为普遍的闲置交易物品处理对象。在这样的背景下,大学校园闲置物品交易平台也应运而生。该平台为在校大学生提供了一个很好的物品交易平台,能够让其物品发挥其最大的利用价值。减少校园中那种铺张浪费的行为。同时也为我们的环保作出一定的贡献价值,该平台根据大学生的实际需求以及校园这种特殊的环境,制定了相应的适合大学生的消费产品,能够给现在的大学在校生的校园生活带来真正的便捷以及相应实际价值。
1.1软件架构
-
后台 :SpringBoot+Mybatis+Shiro+Maven+MySQL
-
前端 :Layui
项目结构导图
1.2 安装教程
-
MySQL 数据库版本 8.0+;application-dev.yml、application-prod.yml修改数据库登录用户名与密码
-
项目中的图片上传用到了阿里云的OSS,没有提供上传到本地的方法,使用自己的阿里云OSS;修改util/OSSClientUtil.java 中的参数
-
util/wechat/WxConsts.java,参数修改成自己小程序的appid和appsecret
-
idea安装lombok插件
-
数据库文件在 resources/static/sql 文件夹中
-
后端登录:用户名:xiaojian;密码:qweqwe
1.3 项目总体框架
2.数据库设计
2.1 表结构
用户表
帖子图片表
帖子表
管理员表
求购表
消息表
举报信息表
商品表
评论表
收藏表
分类表
关注表
2.2 E-R图
3.项目实现
3.2 Shiro过滤器
```java
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 添加 Shiro 内置过滤器
/
* Shiro 内置过滤器,可以实现权限相关的拦截器
* 常用拦截器:
* anon:无需认证(登录)可以访问
* authc:必须认证才可以访问
* user:如果使用 rememberMe 的功能可以直接访问
* perms:该资源必须得到资源权限才可以访问
* role:该资源必须得到角色权限才可以访问
*/
// 添加 Shiro 内置过滤器
Map
// 前端请求数据
// 登录
filterMap.put("/category/getAllCategory","anon");
filterMap.put("/commodity/swiperCommodity","anon");
filterMap.put("/commodity/pageOfCommodity","anon");
filterMap.put("/commodity/commodityDetail/*","anon");
filterMap.put("/commodity/commodityByCategory/*","anon");
filterMap.put("/commodity/updateClickCount/*","anon");
filterMap.put("/seek/pageOfSeek","anon");
filterMap.put("/seek/uploadSeek","anon");
filterMap.put("/seek/search","anon");
filterMap.put("/commodity/uploadData","anon");
filterMap.put("/commodity/uploadCoverImg","anon");
filterMap.put("/commodity/uploadFile","anon");
filterMap.put("/commodity/search","anon");
filterMap.put("/inform/commodityInform","anon");
filterMap.put("/inform/seekInform","anon");
filterMap.put("/inform/topicInform","anon");
filterMap.put("/user/**","anon");
filterMap.put("/topic/pageOfTopic","anon");
filterMap.put("/topic/topicDetail/*","anon");
filterMap.put("/topic/uploadData","anon");
filterMap.put("/topic/uploadFile","anon");
filterMap.put("/topic/updateClickCount/*","anon");
filterMap.put("/topic/addComment","anon");
filterMap.put("/topic/delComment","anon");
filterMap.put("/topic/search","anon");
// 登出
filterMap.put("/logout","logout");
filterMap.put("/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
// 登录页面,点击需要验证的链接,跳转到
shiroFilterFactoryBean.setLoginUrl("/toLogin");
return shiroFilterFactoryBean;
}
/**
* 创建DefaultWebSecurityManager
*/
@Bean
public DefaultWebSecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm());
return securityManager;
}
/**
* 创建Realm
*/
@Bean
public MyRealm myRealm(){
return new MyRealm();
}
/**
* Shiro 生命周期
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
return new LifecycleBeanPostProcessor();
}
/**
* 开启 Shiro 的注解,(@RequireRole,@RequirePermissions),借助 Spring 的AOP扫描使用 Shiro 注解的类,并在需要时进行安全逻辑验证
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor attributeSourceAdvisor(){
AuthorizationAttributeSourceAdvisor attributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
attributeSourceAdvisor.setSecurityManager(securityManager());
return attributeSourceAdvisor;
}
} ```
3.2 执行授权逻辑和认证逻辑
java
public class MyRealm extends AuthorizingRealm {
@Autowired
private SysAdminService sysAdminService;
/**
* 执行授权逻辑
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
/**
* 执行认证逻辑
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 1、获取包含用户名 和 密码的 Token
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
// 2、查询用户名是否存在
SysAdmin user = sysAdminService.findByUsername(token.getUsername());
// 3、如果用户存在
if(user != null){
// 2. 判断密码,返回 AuthenticationInfo 子类
// 第一个参数为 用户名
// 第二个,password 为正确密码
// 第三个,当前realm的名字,可通过父类getName()获得
return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),getName());
} else{
return null;
}
}
}
3.3 HTTP请求工具类
java
public class HttpRequest {
/**
* 向指定 URL 发送 GET 请求
* @param url
* @param param
* @return
*/
public static String sendGet(String url,String param){
String result = "";
BufferedReader in = null;
try {
String urlNameString = url + "?" + param;
URL realUrl = new URL(urlNameString);
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 建立实际的连接
connection.connect();
// 获取所有响应头字段
Map<String, List<String>> map = connection.getHeaderFields();
// 遍历所有的响应头字段
for (String key : map.keySet()) {
System.out.println(key + "--->" + map.get(key));
}
// 定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
/**
* POST 请求
* @param url
* @param param
* @return
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!"+e);
e.printStackTrace();
}
//使用finally块来关闭输出流、输入流
finally{
try{
if(out != null){
out.close();
}
if(in != null){
in.close();
}
}
catch(IOException ex){
ex.printStackTrace();
}
}
return result;
}
3.4 图片云存储工具类
```java public class OSSClientUtil { Log log = LogFactory.getLog(OSSClientUtil.class); //阿里云OSS地址,这里看根据你的oss选择(选用自己的) protected static String endpoint = "xxx"; //阿里云OSS账号(选用自己的) protected static String accessKeyId = "xxx"; //阿里云OSS密钥(选用自己的) protected static String accessKeySecret = "xxx"; //阿里云OSS上的存储块bucket名字(选用自己的) protected static String bucketName = "xxx"; //默认阿里云图片文件存储目录 private String homeimagedir = "commodity/" + StringUtil.getDateForm() + "/";
public String getHomeimagedir() {
return homeimagedir;
}
public void setHomeimagedir(String homeimagedir) {
this.homeimagedir = homeimagedir;
}
private OSSClient ossClient;
public OSSClientUtil() {
ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
}
/**
* 初始化
*/
public void init() {
ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
}
/**
* 销毁
*/
public void destory() {
if(ossClient != null){
ossClient.shutdown();
}
}
/**
* 图片上传阿里云oss,表单上传,更改文件名
* @param file
* @return 文件名
*/
public String uploadHomeImageOSS(MultipartFile file,Boolean randomName) throws Exception {
if (file.getSize() > 1024 * 1024 * 5) {
throw new Exception("上传图片大小不能超过5M!");
}
String originalFilename = file.getOriginalFilename();
String substring = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
String fileName = "";
if(randomName){
Random random = new Random();
fileName = random.nextInt(10000) + System.currentTimeMillis() + substring;
} else{
fileName = originalFilename;
}
try {
InputStream inputStream = file.getInputStream();
this.uploadHomeImageFileOSS(inputStream, fileName);
return fileName;
} catch (Exception e) {
e.printStackTrace();
throw new Exception("图片上传失败");
}
}
/**
* 图片上传到OSS服务器 ,文件流上传
* 如果同名文件会覆盖服务器上的
* @param instream 文件流
* @param fileName 文件名称 包括后缀名
* @return 出错返回"" ,唯一MD5数字签名
*/
public String uploadHomeImageFileOSS(InputStream instream, String fileName) {
String ret = "";
try {
//创建上传Object的Metadata
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(instream.available());
objectMetadata.setCacheControl("no-cache");
objectMetadata.setHeader("Pragma", "no-cache");
objectMetadata.setContentType(getcontentType(fileName.substring(fileName.lastIndexOf("."))));
objectMetadata.setContentDisposition("attachment=filename;");
//上传文件
PutObjectResult putResult = ossClient.putObject(bucketName, homeimagedir + fileName, instream,objectMetadata);
// 唯一MD5数字签名
ret = putResult.getETag();
} catch (IOException e) {
log.error(e.getMessage(), e);
} finally {
try {
if (instream != null) {
instream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return ret;
}
/**
* 判断OSS服务文件上传时文件的类型contentType
*
* @param FilenameExtension 文件后缀
* @return String
*/
public static String getcontentType(String FilenameExtension) {
if (FilenameExtension.equalsIgnoreCase(".bmp")) {
return "image/bmp";
}
if (FilenameExtension.equalsIgnoreCase(".gif")) {
return "image/gif";
}
if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
FilenameExtension.equalsIgnoreCase(".jpg") ||
FilenameExtension.equalsIgnoreCase(".png")) {
return "image/jpeg";
}
if (FilenameExtension.equalsIgnoreCase(".html")) {
return "text/html";
}
if (FilenameExtension.equalsIgnoreCase(".txt")) {
return "text/plain";
}
if (FilenameExtension.equalsIgnoreCase(".vsd")) {
return "application/vnd.visio";
}
if (FilenameExtension.equalsIgnoreCase(".pptx") ||
FilenameExtension.equalsIgnoreCase(".ppt")) {
return "application/vnd.ms-powerpoint";
}
if (FilenameExtension.equalsIgnoreCase(".docx") ||
FilenameExtension.equalsIgnoreCase(".doc")) {
return "application/msword";
}
if (FilenameExtension.equalsIgnoreCase(".xml")) {
return "text/xml";
}
return "image/jpg";
}
/**
* 获得url链接
*
* @param fileName
* @return
*/
public String getUrl(String fileName) {
if(fileName != null){
// 图片完整路径
// 文件url地址路径,精确到文件名上一层目录
String img_src = "https://" + bucketName + "." + endpoint + "/" + homeimagedir + fileName;
return img_src;
}
return null;
}
/**
* 上传图片,并返回图片完整路径
* @param file
* @return
* @throws Exception
*/
public String uploadImageAndGetPath(MultipartFile file,Boolean randomName) throws Exception {
OSSClientUtil ossClient = new OSSClientUtil();
if (file == null || file.getSize() <= 0) {
throw new Exception("图片不能为空");
}
String name = this.uploadHomeImageOSS(file,randomName);
String imgUrl = this.getUrl(name);
return imgUrl;
}
} ```
3.5 主要功能代码
```java
/
* 跳转到商品分类列表页面
*/
@RequestMapping("/toCategory")
public String toSeek(){
return "category/category";
}
/
* 返回分页商品分类列表
*/
@RequestMapping("/categoryList")
@ResponseBody
public Map
result.put("data",categoryList);
result.put("count",categoryService.getCount());
result.put("code",0);
return result;
}
/* * 删除该分类信息 / @PostMapping("/delCategory") @ResponseBody public AjaxResult delCategory(Integer id){ AjaxResult result = null; int count = 0; try{ count = categoryService.deleteCategory(id); if(count > 0){ result = new AjaxResult(true,"删除成功!"); } else{ result = new AjaxResult(false,"删除失败,请联系站长!"); } } catch(Exception e){ result = new AjaxResult(false,"删除失败,多半是该分类下还有商品在出售!"); } return result; }
/ * 跳转到添加分类信息页面 */ @RequestMapping("/toAddCategory") public String toAddCategory(){ return "category/addCategory"; } / * 添加分类信息 */ @PostMapping("/addCategory") @ResponseBody public AjaxResult addCategory(@RequestParam("cateName") String cateName,@RequestParam("sort") Integer sort,@RequestParam("iconFile") MultipartFile multipartFile){ Category category = new Category(); category.setCateName(cateName); category.setSort(sort); AjaxResult result = null; // 上传图片到 阿里云 OSS OSSClientUtil ossClientUtil = new OSSClientUtil(); ossClientUtil.setHomeimagedir("admin/icons/"); try { if(category != null && multipartFile != null){ String img_src = ossClientUtil.uploadImageAndGetPath(multipartFile,false); category.setCateIcon(img_src); int count = categoryService.addCategory(category); if(count > 0){ result = new AjaxResult(true,"添加成功!"); } else{ result = new AjaxResult(false,"上传失败!"); } } } catch (Exception e) { e.printStackTrace(); result = new AjaxResult(false,"图片上传失败!"); } return result; }
/* * 跳转到修改分类信息页面 / @RequestMapping("/toUpdateCategory/{categoryId}") public ModelAndView toUpdateCategory(@PathVariable("categoryId")Integer categoryId){ ModelAndView mav = new ModelAndView(); Category category = categoryService.findById(categoryId);
if(category == null){
mav.addObject("errorMsg","数据请求失败!");
} else{
mav.addObject("category",category);
}
mav.setViewName("category/updateCategory");
return mav;
}
/* * 修改分类信息 / @PostMapping("/updateCategory") @ResponseBody public AjaxResult updateCategory(@RequestParam("id")Integer id, @RequestParam("cateName") String cateName, @RequestParam("sort") Integer sort,@RequestParam("iconFile") MultipartFile multipartFile){ Category category = new Category(); category.setId(id); category.setCateName(cateName); category.setSort(sort); AjaxResult result = null; // 上传图片到 阿里云 OSS OSSClientUtil ossClientUtil = new OSSClientUtil(); ossClientUtil.setHomeimagedir("admin/icons/"); try { if(category != null && multipartFile != null){ String img_src = ossClientUtil.uploadImageAndGetPath(multipartFile,false); category.setCateIcon(img_src); int count = categoryService.updateCategory(category); if(count > 0){ result = new AjaxResult(true,"修改成功!"); } else{ result = new AjaxResult(false,"修改失败!"); } } } catch (Exception e) { e.printStackTrace(); result = new AjaxResult(false,"图片上传失败!"); } return result; } ```
4.项目展示
后台管理首页
商品列表
商品分类
帖子列表
用户列表
举报信息
参考文献
- 基于Spring Boot的校园轻博客系统的设计与实现(华中科技大学·邓笑)
- 基于MVC的高校学生信息管理系统的设计与实现(吉林大学·李昊洋)
- 九江职业大学二手商品交易系统设计与实现(电子科技大学·刘芸琦)
- 推荐算法在校园二手交易平台中的研究与应用(武汉轻工大学·赵壮)
- 九江职业大学二手商品交易系统设计与实现(电子科技大学·刘芸琦)
- 基于MVC的高校学生信息管理系统的设计与实现(吉林大学·李昊洋)
- 基于Spring Boot的校园轻博客系统的设计与实现(华中科技大学·邓笑)
- 基于J2EE的校园二手物品网络预交易系统的设计与实现(山东师范大学·于萧)
- 基于Spring框架的职业院校管理系统构建(复旦大学·王开明)
- 基于Web的智能校园的研究和应用(武汉理工大学·刘玲)
- 高校业务数据管理系统的研究与实现(西安科技大学·高小茜)
- 学生综合信息管理平台的设计与实现(吉林大学·刘铁刚)
- 基于.NET的学生事务管理系统的设计与实现(电子科技大学·郑华)
- 基于.NET的学生事务管理系统的设计与实现(电子科技大学·郑华)
- 基于Spring Boot的学生信息管理系统的设计与实现(武汉轻工大学·杨东)
本文内容包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主题。发布者:代码项目助手 ,原文地址:https://bishedaima.com/yuanma/35504.html