Напишите в начале:
Субъект — студент третьего курса, основной язык — Java, а старшеклассник планирует поехать на стажировку в Ханчжоу.Эта статья на память, а также оставляет некоторые поверхностные идеи для студентов, которым не хватает проектного опыта (кто делает сабж тоже выиграет от открытого исходного кода) как насчет)
Введение проекта:
Это туристический проект на основе SpringBoot с вводным интерфейсом стойки регистрации и системой управления фоном.
Требуются базовые знания: Mybatis+Spring+SpringMVC+SpringBoot+Thymeleaf+ajax+Spring Security
В проекте реализован метод полной аннотации, и нет громоздкого конфигурационного файла.
адрес проекта:GitHub.com/eat by petri или…
Титульная страница
Адрес доступа к стойке регистрации:http://localhost:8080/travel
Фон Главная
Адрес фонового доступа:http://localhost:8080/loginManage
Структура проекта части Java
Пакет 1.config: содержит классы конфигурации и классы аспектов.
2.controller package: содержит класс контроллера
3. пакет dao: содержит интерфейс dao
4.domain пакет: содержит классы сущностей
5. сервисный пакет: содержит сервисный интерфейс и класс реализации интерфейса.
Пакет 6.utils: содержит класс инструментов для загрузки файлов.
1. Классы конфигурации в проекте:
Посетителям необходимо войти в систему для выполнения таких операций, как изменение аватаров, улучшение информации и т. д. Это основная функция веб-сайта.
Реализация этой функции требует использования АОП-программирования в Spring.
Роль класса аспекта LoginAOP: вы должны войти в систему, прежде чем сможете использовать функцию работы пользователя.
Ключ к аспектным классам: когда добавлять какую функциональность к какому методу
Аспект понимается как расширенная функция
Pointcut понимается как набор целевых методов, для которых требуются улучшения
Под советом понимается время исполнения аспекта
Прежде чем использовать пользовательскую операцию, нам нужно определить, вошел ли пользователь в систему.После входа в систему мы можем выполнять последующие операции.Если нет, мы перейдем на страницу входа.
Время, место и что делать ясно, так что если вы запишите это логично, то все будет сделано.
@Aspect
@Component
public class LoginAOP {
//执行用户功能先进入登录切入点
@Pointcut("execution(* com.travel.controller.UserDoController.*(..))")
public void loginPoint(){
}
@Around("loginPoint()")
public Object doBefore(ProceedingJoinPoint joinPoint) throws Throwable {
//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)){
//返回ajax数据
String loginResult = "{\"loginResult\":\"false\"}";
return loginResult;
}else {
return "redirect:/login";
}
}else {
//已登录 可执行目标方法
Object proceed = joinPoint.proceed();
return proceed;
}
}
}
Метод улучшения объемного звучания @Around фактически перехватывает выполнение целевого метода.Перед выполнением целевого метода должен быть выполнен метод объемного звучания.
После успешного или неудачного входа в систему метод может быть передан через
AuthenticationFailureHandler,AuthenticationSuccessHandlerДва интерфейса для достижения, успешный вход переходит на фоновую страницу, неудачный вход перенаправляет на страницу входа
Реализация MyErrorPage
ErrorPageRegistrar, для регистрации различных типов ошибок для отображения разных веб-страниц, основная функция заключается в настройке 404 и других страниц ошибок
public void registerErrorPages(ErrorPageRegistry registry) {
//400: 客户端请求的语法错误
ErrorPage errorPage_400 = new ErrorPage(HttpStatus.BAD_REQUEST,"/error/400");
}
Реализация MyMvcConfig
WebMvcConfigurer, этот класс конфигурацииSpringвнутренняя конфигурация
Вам не нужно писать класс контроллера, вы можете выполнять переходы по страницам с помощью addViewControllers
Каталог сопоставления статических ресурсов также можно настроить в MyMvcConfig.
SpringSecurityРоль: Настройка информации для проверки подлинности и политик проверки подлинности.
Вы можете установить соответствующие разрешения для URL-адреса
http.authorizeRequests().antMatchers("/travel/**").permitAll()
userInfoServiceЯвляется настраиваемым классом, роль этого класса заключается в получении информации о пользователе из базы данных.
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userInfoService);
}
AuthenticationManagerПри аутентификации идентификационной информации пользователя будетuserInfoServiceПолучите удостоверение пользователя и сравните его с удостоверением пользователя, полученным из http.Если сравнение пройдено, последующие операции разрешены.
класс сущности
(1) Форма бронирования отеля (2) Карусельная диаграмма (3) Стол для деликатесов (4) Таблица назначения (5) Стол для гурманов (6) Гостиничный столик (7) Форма сообщения (8) Форма заказа (9) Таблица разрешений (10) Таблица маршрутов (11) Таблица изображений маршрута (12) Ландшафтный стол (13) Таблица информации о пользователе
Очень понятная и понятная система, схемы ER рисовать не буду
Интерфейс Dao: определение методов работы с базой данных
Интерфейс службы и класс реализации интерфейса: определение методов и реализация метода
Класс контроллера: определяет методы обработки запросов.
Приведенный выше код слишком длинный, в основной теме отдельно будет рассказ о работе 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方法
}
Просто определите необходимые свойства
//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 определяет метод запроса имени пользователя и пароля, который используется для входа на главную страницу и запроса имени пользователя и пароля из базы данных.Когда информация в базе данных согласуется с входной информацией, вход прошел успешно.
При многотабличном запросе: необходимо установить отношение сопоставления столбец = "имя поля базы данных" свойство = "атрибут класса объекта"
Также используйте @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);
}
Класс контроллера определяет метод doLogin для ответа на запрос login.do.
Роль объекта сеанса:
Сервер создает объект сеанса для браузера. Когда пользовательские данные необходимо сохранить, серверная программа может записывать пользовательские данные в сеанс исключительно для браузера пользователя. Когда пользователь использует браузер для доступа к другим программам, другие программы могут получить доступ к другим программам из сеанса пользователя. Извлечь данные пользователя, обслужить пользователя и сохранить информацию для входа в сеанс, которая может использоваться в качестве основы для того, вошел ли пользователь в систему.
Класс инструмента: загрузить файл
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;
}
}
Использование фреймворка SpringMultipartFileЭтот класс помогает нам быстро реализовать функцию загрузки файла в виде формы
getOriginalFileNameМетод получает полное имя файла, включая имя файла + расширение файла.
transferToспособ передачи полученного файла по указанному пути назначения
Этапы реализации:
Внешний интерфейс передает файл, получает файл, переименовывает имя файла, сохраняет его по нужному пути и сохраняет изображение.
титульная страница
страница авторизации:Функция, которую необходимо реализовать в интерфейсе входа в систему, — это не что иное, как предоставление пользователю подсказки обратной связи, когда имя пользователя или пароль неверны, и переход на главную страницу системы после успешного входа в систему.
Когда ввод имени пользователя и пароля пуст, будет подсказка, чтобы предложить пользователю
И эта функция подсказки определяетсяValidateTipфункция для реализации
function validateTip(element,css,tipString,status){
element.css(css);
element.attr("placeholder",tipString);
element.attr("validateStatus",status);
}
Когда полученное имя пользователя пусто, измените стиль ввода css на красный, измените tipString на «имя пользователя не может быть пустым» и установите статус на false, чтобы облегчить последующее определение того, является ли имя пользователя пустым, и то же самое верно для установка пароля.
var username = $("#username");
username.on("blur",function () {
if (username.val() == null || username.val() == ""){
validateTip(username,{"border":"2px solid red"},"用户名不能为空",false);
}
});
Когда нажимается кнопка входа, ajax запускает серверlogin.doпросить
Когда возвращенный результат клиентаtrueПри успешном входе текущая страница открывает страницу /travel.
$.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";
}
}
});
Когда возвращенный результат клиентаfalseПри сбое входа текущая страница возвращает страницу с ошибкой.
if (data.loginResult == "false"){
error.show();
error.css("border","2px solid #ea6f5a");
error.html("用户名或密码错误");
}
страница регистрацииПо сравнению со страницей входа, страница регистрации имеет больше ограничений на длину и тип имени пользователя и пароля, для достижения этой функции владелец темы использует регулярные выражения.
//用户名正则表达式,只能由字母数字_-,5-16位
var pattern = /^[a-zA-Z0-9_-]{5,16}$/;
// 密码(6-24位,包括字母,数字,特殊字符[.$@!%*#?&])
var pattern = /^[a-zA-Z0-9.$@!%*#?&]{6,24}$/;
//电话号码正则表达式
var patrn=/^(13[0-9]|15[0-9]|18[0-9])\d{8}$/;
Используйте запрос ajax, чтобы определить, используются ли имя пользователя и номер
Если не используется, можно выполнять обычные операции регистрации.
Реализация суждения Ajax и вышеперечисленное/login.ajaxпохожий
верхняя панель навигации
Панель навигации разделена на две части, левая — это панель навигации, а правая — информация для пользователя.
th:fragment="traveltop"//左边
th:fragment="userInfo"//右边
th:if="${session.userInfo==null}"//说明此时为未登录状态
th:if="${session.userInfo!=null}//说明此时为已登陆状态
Если пользователь авторизовался, будет отображаться страница персонального центра, а если не авторизовался, будет отображаться исходный фрагмент.
титульная страницаДомашняя страница использует каждый цикл для чтения данных и отображения результатов.
<div th:each="destination:${destinations}">
<img th:src="@{${destination.url}}">
</div>
Уровень контроллера использует сервисный уровень.findSixDestinationспособ найти шесть популярных достопримечательностей из базы данных
@RequestMapping(value = "/travel",method = RequestMethod.GET)
public String travel(Model model) throws Exception{
List<Destination> destinations = destinationService.findSixDestination();
model.addAttribute("destinations",destinations);
return "user/travel";
}
Страница сведений о достопримечательностях
Тег видео в html должен установить указанный формат для нормального воспроизведения
Страница рекомендуемого маршрута
Реализация сортировки — это самое старомодное добавление, удаление, модификация и проверка в java.
Шаги: страница инициирует запрос, контроллер вызывает метод службы для обработки запроса, а метод службы вызывает интерфейс dao, который запрашивает данные базы данных.
//按热度查询所有所有热门路线
@Select("select * from route order by heat desc")
@Results({
@Result(id = true,property = "id",column = "id"),
@Result(property = "routePhotoList",column = "id",javaType = List.class,many = @Many(select = "com.travel.dao.RoutePhotoDao.findRoutePhotoByRId"))
})
public abstract List<Route> findAllByHeat() throws Exception;
внештатная страница
Выполните нечеткий запрос к информации базы данных, остальные шаги такие же, как на страницах выше.
//模糊查询用户填写的数据
@Select("select * from route where routeDesc like concat(concat('%',#{month},'%')) and price >= #{minPrice} and price < #{maxPrice} and time >= #{minDay} and time <= #{maxDay} and routeDesc like concat(concat('%',#{dest},'%'))")
страница бронирования отеля
//根据目的地id查询酒店
@Select("select * from hotel where destId=#{destId}")
findHotelsByDestName.ajaxВернуть найденную информацию об отеле после того, как данные будут найдены
search.on("click",function () {
$.ajax({
type:"GET",
url:"/travel/hotel/findHotelsByDestName.ajax",
data:{"destName":destName.val()},
dataType:"json",
success:function (data) {
var str = "";
if (null != data && "" != data){
$.each(data,function (index,hotel) {
str += "<div class=\"row h-item\">" +
"<div class=\"col-lg-3\">" +
"<img src=\"" + hotel.url + "\" class=\"img-rounded\">" +
"</div>" +
"<div class=\"col-lg-9\">" +
"<div class=\"h-info\">" +
"<h4>" + hotel.name + "</h4>" +
"<p>" + hotel.english + "</p>" +
"<p>" + hotel.hotelDesc + "</p>" +
"<p>位置:" + hotel.location + "</p>" +
"<p>价格:" + hotel.price + "</p>" +
'<button hotelId=\"' + hotel.id + '\"' + 'hotelPrice=\"' + hotel.price + '\"' + "class=\"btn btn-warning book-hotel\">立即预定</button>" +
"</div>" +
"</div>" +
"</div>" +
"<hr>";
});
Система фонового управления
Система фонового управления представляет собой визуальную страницу для добавления, удаления, изменения и проверки данных.
Пишите SQL полностью, тогда эта часть так проста
Когда объем фоновых данных относительно велик, можно использовать плагин pagehelper для разбиения данных на страницы.
Напишите в конце:
Уровень письма субъекта и уровень кода ограничены.Если есть какие-либо ошибки, пожалуйста, также спросите Haihan.