写在开头:
题主大三在读生,主语言是Java,大四准备去杭州实习,这篇文章算是留笔纪念,也为缺乏项目经验的同学留下一点浅薄的思路(谁让题主也是代码开源的受益者呢)
项目介绍:
这是一个基于SpringBoot的旅游项目,有前台介绍界面,也有后台管理系统
需要的基础知识:Mybatis+Spring+SpringMVC+SpringBoot+Thymeleaf+ajax+Spring Security
项目采用全注解的实现方式,没有繁琐的配置文件
前台首页
前台访问地址:http://localhost:8080/travel
后台首页
后台访问地址:http://localhost:8080/loginManage
项目中配置类:
定义一个LoginAOP切面类,必须先登录才能使用用户操作功能
切面类需要明白的:什么时候给什么方法增加什么功能
切面 (Aspect) 理解为一个增强的功能
切入点 (Pointcut) 理解为需要增强功能的目标方法的一组集合
通知 (Advice) 理解为切面的执行时间
环绕增强方法实际是拦截了目标方法的执行,在执行目标方法之前,必须执行环绕方法
@Aspect
@Component
public class LoginAOP {
private Logger logger = LoggerFactory.getLogger(getClass());
//执行用户功能先进入登录切入点
@Pointcut("execution(* com.travel.controller.UserDoController.*(..))")
public void loginPoint(){
}
@Around("loginPoint()")
public Object doBefore(ProceedingJoinPoint joinPoint) throws Throwable {
logger.debug("登录环绕通知");
//1.拿到request请求
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
//2.获取session
HttpSession session = request.getSession();
//3.获取userInfo信息
UserInfo userInfo = (UserInfo) session.getAttribute("userInfo");
//4.判断是否登录
if (userInfo == null){
//如果 requestedWith 为 XMLHttpRequest 则为 Ajax 请求
String requestType = request.getHeader("X-Requested-With");
if ("XMLHttpRequest".equals(requestType)){
logger.debug("ajax请求");
//返回ajax数据
String loginResult = "{\"loginResult\":\"false\"}";
return loginResult;
}else {
logger.debug("非ajax请求");
return "redirect:/login";
}
}else {
//已登录 可执行目标方法
Object proceed = joinPoint.proceed();
return proceed;
}
}
}
复制代码
通过AuthenticationFailureHandler
,AuthenticationSuccessHandler
接口,可以自定义登录成功失败类
MyErrorPage实现ErrorPageRegistrar
,来注册不同错误类型显示不同的网页
MyMvcConfig实现WebMvcConfigurer
,这个配置类是Spring
内部的一种配置方式
SpringSecurity
:配置认证信息和认证策略
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userInfoService);
}
复制代码
userInfoService
是自定义的类, 这个类的作用就是从数据库中获取用户信息。AuthenticationManager
在认证用户身份信息的时候,就会从中获取用户身份,和从http中拿的用户身份做对比。
实体类
(1)预定酒店表 (2)轮播图表 (3)美食店表 (4)目的地表 (5)美食表 (6)酒店表 (7)留言表 (8)订单表 (9)权限表 (10)路线表 (11)路线图片表 (12)风景表 (13)用户信息表
很清晰明了的系统,ER图我就不画了吧
Dao接口:定义操作数据库的方法
Service接口和接口实现类:定义方法和方法实现
Controller类:定义处理请求的方法
以上代码篇幅过长 题主就单独把UserInfo的操作拎出来讲讲
//domain层
public class UserInfo {
private Integer id;//用户id,自增长
private String username;//用户名
private String password;//用户密码
private String phoneNum;//用户电话号码
private String email;//用户邮箱
private String url;//用户头像地址
private Integer status;//用户状态
private String statusStr;//转化用户状态
private Integer gender;//用户性别
private String intro;//用户简介
private List<Role> roles;//用户所有权限
//get,set方法
//重写toString方法
}
复制代码
就定义需要的属性就OK了
//dao层
@Mapper
public interface UserInfoDao {
//前台旅游网站登录
@Select("select * from user where username=#{username} and password=#{password}")
public UserInfo findUser(@Param("username") String Username, @Param("password") String Password) throws Exception;
}
复制代码
dao层定义了一个查询用户名称和密码的方法,用来前台页面的登录
当多表查询时:需要建立映射关系 column="数据库字段名" property="实体类属性"
还要使用@One或者@Many调用相应的方法
//service层定义的接口
public interface UserInfoService extends UserDetailsService {
//前台用户登录
public UserInfo findUser(String username, String password) throws Exception;
}
//service层定义的接口实现类
@Service
public class UserInfoServiceImpl implements UserInfoService {
@Resource
private UserInfoDao userInfoDao;
@Override
public UserInfo findUser(String username,String password) throws Exception {
return userInfoDao.findUser(username,password);
}
}
复制代码
Service类调用dao接口实现登录功能
//SpringSecurityController定义方法处理登录请求
//用户执行登录操作
@RequestMapping(value = "/login.do",method = RequestMethod.POST)
@ResponseBody
public Object doLogin(@RequestParam("username") String username,
@RequestParam("password") String password,
HttpSession session) throws Exception{
HashMap<String,String> loginResult = new HashMap<String, String>();
UserInfo userInfo = userInfoService.findUser(username,password);
if (userInfo != null){
if (userInfo.getStatus() == 1){
//用户名密码正确,并且账号状态可用
session.setAttribute("userInfo",userInfo);
loginResult.put("loginResult","true");
}else {
//账号不可用
loginResult.put("loginResult","forbid");
}
}else {
//用户名或密码错误
loginResult.put("loginResult","false");
}
return JSONArray.toJSONString(loginResult);
}
复制代码
controller类定义doLogin方法对login.do请求做出响应
服务器为浏览器创建一个会话对象(session对象),在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务,将登录信息保存在session中,可以作为用户是否登录的依据
工具类:上传文件
public class UploadFileUtils {
public static String uploadImgFile(MultipartFile file,String param) throws IOException {
//1.获取文件的原名称
String originalFilename = file.getOriginalFilename();
//2.获取文件的后缀
String suffixName = originalFilename.substring(originalFilename.lastIndexOf("."));
//3.生成新的文件名
String newFilename = UUID.randomUUID().toString().replace("-","") + System.currentTimeMillis() + suffixName;
//4.保存的位置
String localFilename = "F:\\Springboot\\18_jxnu\\src\\main\\resources\\static\\images\\" + param + File.separator + newFilename;
//5.将位置转化为文件对象
File desFile = new File(localFilename);
//6.将上传的文件以新的文件名保存到到服务器上
file.transferTo(desFile);
//7.上传成功
System.out.println("上传至服务器成功");
//8.返回新文件名,以便继续后面的操作
return newFilename;
}
}
复制代码
Spring框架使用MultipartFile
这个类来实现以表单的形式进行文件上传功能
MultipartFile
类中提供了方法方便我们直接获取文件和对文件的操作
getOriginalFileName
方法获取的是文件的完整名称,包括文件名称+文件拓展名
transferTo
方法用来将接收文件传输到给定目标路径
登录ajax
function validateTip(element,css,tipString,status){
element.css(css);
element.attr("placeholder",tipString);
element.attr("validateStatus",status);
}
$(function () {
var username = $("#username");
var password = $("#password");
var submit = $("#submit");
var error = $("#error");
submit.on("click",function () {
if (username.attr("validateStatus") != "true"){
username.blur();
} else if (password.attr("validateStatus") != "true"){
password.blur();
} else {
$.ajax({
type:"POST",
url:"/login.do",
data:{"username":username.val(),"password":password.val()},
dataType:"json",
success:function (data) {
if (data.loginResult == "true"){
location.href = "/travel";
}else if (data.loginResult == "forbid") {
error.show();
error.css("border","2px solid #ea6f5a");
error.html("账号已被禁用");
setTimeout(function () {
error.fadeOut(1000);
},1000);
}else if (data.loginResult == "false"){
error.show();
error.css("border","2px solid #ea6f5a");
error.html("用户名或密码错误");
setTimeout(function () {
error.fadeOut(1000);
},1000);
}
},
error:function () {
alert("服务器繁忙");
}
});
}
});
}
复制代码
点击按钮发起login.do的ajax请求,对当前账号的信息进行判断,不同情况返回不同的结果
项目中还使用了正则表达式对注册的用户信息进行限制等等
......代码太多了,看源码自行体会吧
作者:十二时辰_
链接:https://juejin.cn/post/6954330325245755423
来源:掘金