Personally, I suggest this project is quite good. There are many places to think about
Introduction to the technology and environment used
Environment configuration
Technical layer selection
-
Web layer
Servlet Front end controller Html View data display effect display Filter filter Beanutils Data encapsulation Jackson json Serialization tool
-
Service layer
Javamail Mail send mail Redis nosql Memory database Jedis java of redis Client for
-
Dao layer data access layer
Mysql database Druid Database connection pool JdbcTempalte jdbc Tools for
The server uses Tomcat database mysql
Maven is loaded when importing the corresponding pom.xml
Filter to prevent garbled code
//Convert parent interface to child interface HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) rep; //Get request method String method = request.getMethod(); //Solve the problem of Chinese data garbled in post request if(method.equalsIgnoreCase("post")){ request.setCharacterEncoding("utf-8"); } //Processing response garbled code response.setContentType("text/html;charset=utf-8"); filterChain.doFilter(request,response);
Project structure
Registration function form display
Register.html
Using js to complete form verification
Form submission using ajax
After registration, jump to the success page
regisUserServlet
get data
Encapsulating User objects
Call service to complete registration
According to the prompt returned by the service
1. Convert the prompt information to json
2. Set the response header contenttype
After the corresponding registration form is submitted, the back-end processing core code is clear about the session domain to prevent the validation code from being invalid due to refresh
@WebServlet("/registerUserServlet") public class RegisUserServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // Verification Code String check = req.getParameter("check"); // Get from session HttpSession session = req.getSession(); String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER"); // Clear the Session session domain and ensure that the verification code can only be used once session.removeAttribute("CHECKCODE_SERVER"); // compare if(checkcode_server == null || !checkcode_server.equalsIgnoreCase(check)){ // Verification code error ResultInfo info = new ResultInfo(); // login has failed info.setFlag(false); info.setErrorMsg("Verification code error"); // Serialize info object as json ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(info); resp.setContentType("application/json;charset=utf-8"); resp.getWriter().write(json); return ; } Map<String, String[]> map = req.getParameterMap(); User user = new User(); try { BeanUtils.populate(user,map); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } // Call service to complete registration UserService service = new UserServiceImpl(); boolean flag= service.regist(user); ResultInfo info = new ResultInfo(); // Response results if(flag){ // login was successful info.setFlag(true); }else{ // login has failed info.setFlag(false); info.setErrorMsg("login has failed"); } // Serialize info object as json ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(info); // Write json data back to the client // Set content type resp.setContentType("application/json;charset=utf-8"); resp.getWriter().write(json); }
After registration, a mailbox will be registered. Activation authentication requires mailbox verification
Display of tools
/** * Email tool class */ public final class MailUtils { private static final String USER = ""; // Sender's title, same as email address private static final String PASSWORD = ""; // If it is a qq mailbox, you can use the client authorization code or login password /** * * @param to Recipient mailbox * @param text Message body * @param title title */ /* Send verification message */ public static boolean sendMail(String to, String text, String title){ try { final Properties props = new Properties(); props.put("mail.smtp.auth", "true"); props.put("mail.smtp.host", "smtp.qq.com"); // Sender's account number props.put("mail.user", USER); //Sender's password props.put("mail.password", PASSWORD); // Build authorization information for SMTP authentication Authenticator authenticator = new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { // User name and password String userName = props.getProperty("mail.user"); String password = props.getProperty("mail.password"); return new PasswordAuthentication(userName, password); } }; // Create a mail session using environment properties and authorization information Session mailSession = Session.getInstance(props, authenticator); // Create mail message MimeMessage message = new MimeMessage(mailSession); // Set sender String username = props.getProperty("mail.user"); InternetAddress form = new InternetAddress(username); message.setFrom(form); // Set recipient InternetAddress toAddress = new InternetAddress(to); message.setRecipient(Message.RecipientType.TO, toAddress); // Set message header message.setSubject(title); // Set the content body of the message message.setContent(text, "text/html;charset=UTF-8"); // Send mail Transport.send(message); return true; }catch (Exception e){ e.printStackTrace(); } return false; }
When the user activates again
Enter UserDaoimpl to modify and add code logic to store status and code
Background code implementation
Write RegisUserServlet
Write UserService and UserSericelmpl
Write UserDao and UserDaoImpl
Login function form display
Form submission in login page
$(function () { // Bind a click event to the login button $("#btn_sub").click(function(){ // Send an ajax request to submit form data $.post("user/login",$("#loginForm").serialize(),function (data){ // data : {flag:false ,errorMsg:''} if(data.flag){ // Login succeeded location.href="index.html" }else{ // Login failed $("#errorMsg").html(data.errorMsg); } }); }); });
Prompt information function of user name in index page‘
After login, you need to save the user name to session Welcome to the back: users use
if(u !=null && "Y".equals(u.getStatus())){ // Login succeeded info.setFlag(true); // After successful login, the name obtained in the page will be saved into the session and displayed as the login name req.getSession().setAttribute("user",u); }
Corresponding findUserServlet
// Get login user from session Object user = req.getSession().getAttribute("user"); // Write user back to client ObjectMapper mapper = new ObjectMapper(); resp.setContentType("application/json;charset=utf-8"); mapper.writeValue(resp.getOutputStream(),user);
The login condition is that there is a user object in the session
Implementation steps
Access the servlet to destroy the session
Jump to login page
Three corresponding situations for login success judgment "
//Three login types corresponding to login
//1 there may not be a fixed user name for drinking
//2. The account and password are correct, but there is no correct activation status
//3. The account number and password are saved correctly
Optimize the servlet method for extraction
Reducing the number of servlets is now a Servlet, which is optimized into a module. A Servlet is equivalent to a table corresponding to a Servlet in the database. Different methods are provided in the Servlet to complete the user's request
Intermediate inheritance method BaseServlet
Complete the distribution of methods, get the final path method name, obtain the method object, and execute the method through reflection
// Inherit HttpServlet and implement the corresponding service method @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // Complete the method distribution, get the method name at the end of the path, obtain the method object, and execute the method in a reflective manner // Get request path String uri=req.getRequestURI(); // user/add // Get method name String methodName = uri.substring(uri.lastIndexOf('/')+1); // Get Method object Method try { // Ignore access modifier get method Method method = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); // Execution method // Violent reflex method.setAccessible(true); method.invoke(this,req,resp); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } // The extraction of methods directly improves the use of corresponding methods and reduces the redundancy of codes // Serialize the incoming object directly into json and write it back to the client public void writeValue(Object obj, HttpServletResponse resp) throws IOException { // Serialize json return ObjectMapper mapper = new ObjectMapper(); resp.setContentType("application/json;charset=utf-8"); mapper.writeValue(resp.getOutputStream(),obj); } // Serialize the incoming object as a json return public String writeValueAsString(Object obj) throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); return mapper.writeValueAsString(obj);
Set character parameters and solve the problem of console garbled Code: garbled code will appear
File—Build —Maven — Runner –VM Options --Dfile.encodeing=gb2312
Classified data display function
Existing problems: Each refresh will request the database to load classification data, and the classification data will not change frequently, The pressure on the database is great. Cache is used to reduce the number of accesses to the database Query efficiency is high, so it is used redis Cache
Index.html contains header.html
Send an ajax request to access the server to load the real classification data
Traversal array
CateaggeoryServlet
FindAll(){ call Servlet query list take List Serialize collection to json return
}
CateaggeoryServlet
private CategoryService service = new CategoryServiceImpl(); // Query all classified data display public void findAll(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // Call service to query all List<Category> cs = service.findAll(); // Serialize json return ObjectMapper mapper = new ObjectMapper(); resp.setContentType("application/json;charset=utf-8"); mapper.writeValue(resp.getOutputStream(),cs);
Corresponding FindAll
// Control the display of the corresponding cid rname and the corresponding page number @Override public List<Category> findAll() { // Query from redis // Get jedis client Jedis jedis = JedisUtil.getJedis(); // Query the score (cid) and value (cname) in sortedset Set<Tuple> categorys = jedis.zrangeWithScores("category", 0, -1); List<Category> cs = null; // Judge whether the query set is empty if (categorys == null || categorys.size() == 0) { // If it is empty, you need to query from the database and store the data in redis // Query from database cs = categoryDao.findAll(); // Store the collection data in the key of category in redis for (int i = 0; i < cs.size(); i++) { jedis.zadd("category", cs.get(i).getCid(), cs.get(i).getCname()); } } else { // If it is not empty, the data of set is stored in the List. The query is set, but the List set is required to return, so the conversion between sets is carried out cs = new ArrayList<Category>(); for (Tuple tuple : categorys) { Category category = new Category(); category.setCname(tuple.getElement()); category.setCid((int)tuple.getScore()); cs.add(category); } } return cs;
Cache optimization of classified data
After each page load, the classified data will re request the database to load, which puts great pressure on the database, and the classified data does not change frequently, so redis can be used to cache this data
Cache optimization with redis
In CategoryService
Query whether it is null from redis
yes
Access the query database for the first time and store the database in redis
no
Not the first visit
Return collection
CateoryDao
Both execute the dindAll() method
Don't forget to open redis when using it
reids Open win+R cd Enter the corresponding redis folder use redis-server.exe redis.windows.conf reids Open win+R cd Enter the corresponding redis folder use redis-server.exe redis.windows.conf If not, use the following command redis-client.exe shutdown exit Then use the above command again
Pagination display of tourist routes
Click to find that the tourist routes seen in the future are different after different classifications. Send a many-to-one relationship between the tourist route table and the classification table by analyzing the database table structure
It is realized through the following three class functions
RouteSerlvet
RouteService
RouteDao
Select * from tab_route where cid = ? ;
Query score(cid) in Redis
'
- <a Href ="source_list.html?cid = '+data[i].cid+'">'+data[i].cname+'
-
Passing of category id
Redis Medium query score(cid) Page delivery cid Header.html transmit cid
Display tourism route data in pages
In the synchronization mode, you can put the data into the request field, and use the foreach tag and el expression in the jsp to traverse the data to generate data
Html can only display foreground pages asynchronously
Client page
The ajax request sent by the client page requests the data of the PageBean
Carry parameters
currentPage (current page number)
PageSize (number of items displayed per page)
CID (paging cid)Respond and process the RouteServlet. The judgment conditions here need to be null judged to prevent the occurrence of null pointers
public void pageQuery(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Accept three parameters String currentPageStr = request.getParameter("currentPage"); String pageSizeStr = request.getParameter("pageSize"); String cidStr = request.getParameter("cid"); //Accept rname line name // When obtaining the corresponding rname, you need to make corresponding conditions. No, the corresponding null pointer exception will be caused when the rname is not entered // In particular, when you click the second page during pagination query, the data will not be displayed normally String rname = request.getParameter("rname"); if(rname!= null && rname.length()>0 && !"null".equals(rname)){ rname = new String(rname.getBytes("iso-8859-1"),"utf-8"); } int cid = 0;//Category id // Handle parameters to prevent null pointer exceptions if(cidStr != null && cidStr.length() > 0 && !"null".equals(cidStr)){ cid = Integer.parseInt(cidStr); } //The current page number. If it is not passed, it defaults to the first page int currentPage = 0; if(currentPageStr != null && currentPageStr.length() > 0 ){ currentPage = Integer.parseInt(currentPageStr); }else{ currentPage = 1; } //The number of records is displayed on each page. If it is not transferred, 5 records are displayed on each page by default int pageSize = 0; if(pageSizeStr != null && pageSizeStr.length() > 0 ){ pageSize = Integer.parseInt(pageSizeStr); }else{ pageSize = 5; } // Call service to query PageBean object PageBean<Route> pb = routeService.pageQuery(cid, currentPage, pageSize,rname); // Serialize the pageBean object into json and return writeValue(pb,response);
The server-side PageBean will be serialized as json and returned to the client
// Paging object // Encapsulate parameters into PageBean public class PageBean<T> { private int totalCount; // Total records private int totalPage; // PageCount private int currentPage; // Current page number private int pageSize; // Number of items displayed per page private List<T> list;//Data set displayed per page
Corresponding PgeQuery
public void pageQuery(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Accept three parameters String currentPageStr = request.getParameter("currentPage"); String pageSizeStr = request.getParameter("pageSize"); String cidStr = request.getParameter("cid"); //Accept rname line name // When obtaining the corresponding rname, you need to make corresponding conditions. No, the corresponding null pointer exception will be caused when the rname is not entered // In particular, when you click the second page during pagination query, the data will not be displayed normally String rname = request.getParameter("rname"); if(rname!= null && rname.length()>0 && !"null".equals(rname)){ rname = new String(rname.getBytes("iso-8859-1"),"utf-8"); } int cid = 0;//Category id // Handle parameters to prevent null pointer exceptions if(cidStr != null && cidStr.length() > 0 && !"null".equals(cidStr)){ cid = Integer.parseInt(cidStr); } //The current page number. If it is not passed, it defaults to the first page int currentPage = 0; if(currentPageStr != null && currentPageStr.length() > 0 ){ currentPage = Integer.parseInt(currentPageStr); }else{ currentPage = 1; } //The number of records is displayed on each page. If it is not transferred, 5 records are displayed on each page by default int pageSize = 0; if(pageSizeStr != null && pageSizeStr.length() > 0 ){ pageSize = Integer.parseInt(pageSizeStr); }else{ pageSize = 5; } // Call service to query PageBean object PageBean<Route> pb = routeService.pageQuery(cid, currentPage, pageSize,rname); // Serialize the pageBean object into json and return writeValue(pb,response); }
Fuzzy query of tourist route name
Transfer of query parameters -------------------------- click the search button to trigger the search event
In header.html
Set the id binding response event for the button$(function () { // Query classification data // Sets the path that determines data access $.post("category/findAll",{},function (data) { var lis = ' <li class="nav-active"><a href="index.html">home page</a></li>'; // Traversal array concatenation string for(var i =0; i<data.length; i++){ // Later, access and query the corresponding database content according to cid var li = '<li><a href="route_list.html?cid='+data[i].cid+'">'+data[i].cname+'</a><li>'; lis += li; } //Mosaic collection Leaderboard lis+'<li><a href="favoriterank.html">Collection ranking</a></li>'; // Set the lis string to the html content of ul $("#category").html(lis); }); // Bind the click event to the search button to get the content of the search input box $("#search-button").click(function () { // A line name is required for fuzzy matching var rname=$("#search_input").val(); // Jump path for splicing var cid=getParameter("cid"); location.href="http://localhost/travel/route_list.html?cid="+cid+"&rname="+rname; }); });
Modify background code
Enter CategoryServlet first and call service.findAll()
Corresponding to entering categoryDao, call categoryDao.findAll();// Call service to query all List<Category> cs = service.findAll();
Corresponding findAll
private CategoryDao categoryDao = new CategoryDaoImpl(); // Control the display of the corresponding cid rname and the corresponding page number @Override public List<Category> findAll() { // Query from redis // Get jedis client Jedis jedis = JedisUtil.getJedis(); // Query the score (cid) and value (cname) in sortedset Set<Tuple> categorys = jedis.zrangeWithScores("category", 0, -1); List<Category> cs = null; // Judge whether the query set is empty if (categorys == null || categorys.size() == 0) { // If it is empty, you need to query from the database and store the data in redis // Query from database cs = categoryDao.findAll(); // Store the collection data in the key of category in redis for (int i = 0; i < cs.size(); i++) { jedis.zadd("category", cs.get(i).getCid(), cs.get(i).getCname()); } } else { // If it is not empty, the data of set is stored in the List. The query is set, but the List set is required to return, so the conversion between sets is carried out cs = new ArrayList<Category>(); for (Tuple tuple : categorys) { Category category = new Category(); category.setCname(tuple.getElement()); category.setCid((int)tuple.getScore()); cs.add(category); } } return cs; }
Query of Dao database
// Query all corresponding data public List<Category> findAll() { List<Category> list = new ArrayList<>(); try{ String sql = "select * from tab_category"; list = template.query(sql,new BeanPropertyRowMapper<>(Category.class)); }catch (Exception e){ } return list; }
Return the result set and fill the corresponding data to the front position
View details
Route_detail.html? rid =1
When the page number is loaded, send an ajax request to query the Route objectView the hyperlink corresponding to the details Then bind to the hyperlink ird Send when page number is loaded ajax Request query route object RouteServlet findOne(){ receive rid call service query transformation json return } RouteService Findone( int rid){ 1 according to id query route object RouteDao 2 according to rid Route id query Tab_route_img Set collection to route object 3 according to sid seller id query tab_seller Query the seller information and set it to route object }
Corresponding findOne method
public void findOne(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Receive parameter id String rid = request.getParameter("rid"); // Call the service to query the route object Route route = routeService.finOne(rid); // Convert to json and write back to the client writeValue(route,response); }
Query routeService according to the corresponding rid conditions
Route route = routeDao.finOne(Integer.parseInt(rid)); // Query the picture collection information according to the id of the route List<RouteImg> routeImgList = routeImgDao.finByRid(route.getRid()); // Set the collection to the route object route.setRouteImgList(routeImgList); Seller seller = sellerDao.findByid(route.getSid()); route.setSeller(seller);
Visit the following three Dao s
RouteDao
RouteImplDao
SellerDaoCall three Dao
Foreground code Route_detail.html After loading in obtain rid send out ajax Request acquisition route object Parsing object data
Tourist route collection function
analysis
Judge whether the current login user has collected the line
When the page is loaded, send an ajax request to get the tag whether the user likes it or not
Transfer line id rid
Request the corresponding RouteServlet according to the unused button style displayed by the tag
Get rid line id
Gets the currently logged in user object session
If the user object is null, set the bar uid =0call FavoriteService Query delivery rid uid Writeback client flag sign
FavoriteService
isFavorite(rid , uid)
FavoriteDao
findByUi dan Rid(uid rid)Route_detai.html
Dynamic display of collection times
Click the button of the favorite line
The foreground judges whether the user logs in
If you log in, you can click the button
No prompt is given for login
Send AJAX request
RouteServlet
Get rid of the line
Get user's uid
Call service to addFavoriteServlet add method
// Get line id String rid = request.getParameter("rid"); // Get the currently logged in user User user = (User) request.getSession().getAttribute("user"); int uid; if(user == null){ return ; }else{ uid= user.getUid(); } // Call service to add favoriteService.add(rid,uid); }
FavoriteDao add method
public void add(int rid, int uid) { String sql = "insert into tab_favorite value(?,?,?)"; template.update(sql,rid,new Date(),uid); }
Personal summary overall project
I personally make mistakes and difficulties
Profile version
Corresponding null pointer error reporting exception handling
Character input error on details case error
Code processing of paging
queryForObject has and can only query one piece of data. If there is no such data in the database or the data in the database is the same, an exception will be thrown
This is mainly because there is no correct corresponding information during data query
Throw an exception and use try catch
The BaseServlet extracts various annotations
First, the servlet layer calls the service layer to implement the class, calls the dao layer to look up the table, calls and executes sql statements to return the query resultsWelcome to leave a message to discuss problems