current position:Home>The ultimate actual combat of the most complete tourism project based on spring boot + Vue front-end and back-end separation in history (with source code attached), none of them!!!

The ultimate actual combat of the most complete tourism project based on spring boot + Vue front-end and back-end separation in history (with source code attached), none of them!!!

2022-05-15 02:47:36@The road of youth

List of articles

Write it at the front : Welcome bloggers to read my blog , I hope you can gain something from this blog . If there are any questions , Welcome to comment in the comment area . Due to my limited level , If there is any deficiency , Please correct me , thank you !

Presumably, the guys also saw through the title of the blog , This is one about Spring Boot+Vue A practical project of separating the front and rear ends of tourism information management system . Okay , Don't talk much , Let's take a brief look at the effect of the interface !
 Insert picture description here
 Insert picture description here

Pre knowledge preparation :

① Front end technology stack :Vue、nodejs
② Back end technology stack : Spring Boot + MyBatis
③ Front and rear communication mode :axios json

Next, I will start from the demand analysis → Library table design → code ( Project environment construction + Project code ) → Project debugging to achieve a complete project .

One 、 Demand analysis

1、 User module : Sign in and sign up

2、 Province module :CRUD( Additions and deletions )

3、 Attraction module :CRUD( Additions and deletions )

Two 、 Library table design

Before you create the table , We need to create a database first , Use the following statement .

CREATE DATABASE travel DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

All right. , The database has been established , Next, let's create a user table 、 List of provinces and scenic spots .

--  User table  
create table t_user(
	id int(6) PRIMARY key auto_increment,
	username varchar(60),
	password varchar(60),
	email varchar(60)
);


--  Province table 
create table t_province(
	id int(6) PRIMARY key auto_increment,
	name varchar(60),
	tags varchar(80),
	placecounts int(4)
);

--  List of scenic spots 
create table t_place(
	id int(6) PRIMARY key auto_increment,
	name varchar(60),
	picpath varchar(100),
	hottime TIMESTAMP,
	hotticket double(7,2),
	dimticket double(7,2),
	placedes varchar(300),
	provinceid int(6) REFERENCES t_province(id)
);

3、 ... and 、 Project code

Let's take a look at the overall structure of the project !
 Insert picture description here

1、 Environment building

(1) Dependencies required to import the environment

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
</dependencies>

(2)application.yml Project configuration information

# Port number configuration 
server:
  port: 8080

# Data source configuration 
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/travels?characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: 123456
    type: com.alibaba.druid.pool.DruidDataSource

  # Static resource path 
  resources:
    static-locations: file:${
    upload.dir}

  servlet:
    multipart:
      #  Set the size of a single file 
      max-file-size: 50MB
      max-request-size: 50MB

#mybatis Related configuration 
mybatis:
  # To configure MyBatis Of xml Profile path 
  mapper-locations: classpath:com/uos/travels/mapper/*.xml
  # To configure XML The entity class alias path specified in the mapping file 
  type-aliases-package: com.uos.travels.entity

#  Configure log level 
logging:
  level:
    root: info
    com.uos.travels.dao: debug


#  File upload configuration 
upload:
  dir: E:/travels/images

(3) Static resource import

Static resources gitee Address , Please click this link to visit
 Insert picture description here
Put the downloaded resources into static Under the table of contents . You can download it directly zip Compressed package , Of course you can also use commands
git clone https://gitee.com/chuzhuyong/travels_static.git Clone resources to local .

2、 User module development

(1) User registration + The user login The back-end processing

① stay entity Package under the new User Entity class

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    
    private String id;
    private String username;
    private String password;
    private String email;
}

here , We also create a new entity class Result, This class is mainly used for controller The result object returned in .

@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Result {
    
    private Boolean state = true;
    private String message;
    private String userId;
}

ad locum , Some friends may have questions . I've used it before lombok Of @Data、@NoArgsConstructor、@AllArgsConstructor annotation , But here @Accessors(chain = true) What's the use of annotations ?

Give me a chestnut , Please see the difference between the following codes .

Not used @Accessors(chain = true) Previous set Here's how it works .

public void setMessage(String message) {
    
        this.message = message;
}

Use @Accessors(chain = true) After that set Here's how it works .

public Result setMessage(final String message) {
    
        this.message = message;
        return this;
}

Come here , The little friends can see the difference . Use @Accessors(chain = true) The return value is this, The main advantage of this annotation is its convenience cascade operation .

② stay utils Create a new picture verification code class under the package

public class CreateImageCode {
    
    //  Width of picture .
    private int width = 160;
    //  Height of picture .
    private int height = 40;
    //  Number of verification code characters 
    private int codeCount = 4;
    //  The number of captcha interference lines 
    private int lineCount = 20;
    //  Verification Code 
    private String code = null;
    //  Captcha image Buffer
    private BufferedImage buffImg = null;
    Random random = new Random();

    public CreateImageCode() {
    
        creatImage();
    }

    public CreateImageCode(int width, int height) {
    
        this.width = width;
        this.height = height;
        creatImage();
    }

    public CreateImageCode(int width, int height, int codeCount) {
    
        this.width = width;
        this.height = height;
        this.codeCount = codeCount;
        creatImage();
    }

    public CreateImageCode(int width, int height, int codeCount, int lineCount) {
    
        this.width = width;
        this.height = height;
        this.codeCount = codeCount;
        this.lineCount = lineCount;
        creatImage();
    }

    //  Generate pictures 
    private void creatImage() {
    
        int fontWidth = width / codeCount;//  The width of the font 
        int fontHeight = height - 5;//  The height of the font 
        int codeY = height - 8;

        //  Images buffer
        buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g = buffImg.getGraphics();
        //Graphics2D g = buffImg.createGraphics();
        //  Set background color 
        g.setColor(getRandColor(200, 250));
        g.fillRect(0, 0, width, height);



        //  Set the font 
        //Font font1 = getFont(fontHeight);
        Font font = new Font("Fixedsys", Font.BOLD, fontHeight);
        g.setFont(font);

        //  Set the interference line 
        for (int i = 0; i < lineCount; i++) {
    
            int xs = random.nextInt(width);
            int ys = random.nextInt(height);
            int xe = xs + random.nextInt(width);
            int ye = ys + random.nextInt(height);
            g.setColor(getRandColor(1, 255));
            g.drawLine(xs, ys, xe, ye);
        }

        //  Add noise 
        float yawpRate = 0.01f;//  Noise rate 
        int area = (int) (yawpRate * width * height);
        for (int i = 0; i < area; i++) {
    
            int x = random.nextInt(width);
            int y = random.nextInt(height);

            buffImg.setRGB(x, y, random.nextInt(255));
        }


        String str1 = randomStr(codeCount);//  Get random characters 
        this.code = str1;
        for (int i = 0; i < codeCount; i++) {
    
            String strRand = str1.substring(i, i + 1);
            g.setColor(getRandColor(1, 255));
            // g.drawString(a,x,y);
            // a For what you want to draw ,x and y The baseline of the leftmost character representing the thing to be drawn is located at the bottom of the drawing context coordinate system  (x, y)  Location 

            g.drawString(strRand, i*fontWidth+3, codeY);
        }


    }

    //  Get random characters 
    private String randomStr(int n) {
    
        String str1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
        String str2 = "";
        int len = str1.length() - 1;
        double r;
        for (int i = 0; i < n; i++) {
    
            r = (Math.random()) * len;
            str2 = str2 + str1.charAt((int) r);
        }
        return str2;
    }

    //  Get random colors 
    private Color getRandColor(int fc, int bc) {
    //  Get random colors for a given range 
        if (fc > 255)
            fc = 255;
        if (bc > 255)
            bc = 255;
        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }

    /** *  Generate random Fonts  */
    private Font getFont(int size) {
    
        Random random = new Random();
        Font font[] = new Font[5];
        font[0] = new Font("Ravie", Font.PLAIN, size);
        font[1] = new Font("Antique Olive Compact", Font.PLAIN, size);
        font[2] = new Font("Fixedsys", Font.PLAIN, size);
        font[3] = new Font("Wide Latin", Font.PLAIN, size);
        font[4] = new Font("Gill Sans Ultra Bold", Font.PLAIN, size);
        return font[random.nextInt(5)];
    }

    //  Twist method 
    private void shear(Graphics g, int w1, int h1, Color color) {
    
        shearX(g, w1, h1, color);
        shearY(g, w1, h1, color);
    }

    private void shearX(Graphics g, int w1, int h1, Color color) {
    

        int period = random.nextInt(2);

        boolean borderGap = true;
        int frames = 1;
        int phase = random.nextInt(2);

        for (int i = 0; i < h1; i++) {
    
            double d = (double) (period >> 1)
                    * Math.sin((double) i / (double) period
                    + (6.2831853071795862D * (double) phase)
                    / (double) frames);
            g.copyArea(0, i, w1, 1, (int) d, 0);
            if (borderGap) {
    
                g.setColor(color);
                g.drawLine((int) d, i, 0, i);
                g.drawLine((int) d + w1, i, w1, i);
            }
        }

    }

    private void shearY(Graphics g, int w1, int h1, Color color) {
    

        int period = random.nextInt(40) + 10; // 50;

        boolean borderGap = true;
        int frames = 20;
        int phase = 7;
        for (int i = 0; i < w1; i++) {
    
            double d = (double) (period >> 1)
                    * Math.sin((double) i / (double) period
                    + (6.2831853071795862D * (double) phase)
                    / (double) frames);
            g.copyArea(i, 0, 1, h1, 0, (int) d);
            if (borderGap) {
    
                g.setColor(color);
                g.drawLine(i, (int) d, i, 0);
                g.drawLine(i, (int) d + h1, i, h1);
            }

        }

    }
    
    public void write(OutputStream sos) throws IOException {
    
        ImageIO.write(buffImg, "png", sos);
        sos.close();
    }

    public BufferedImage getBuffImg() {
    
        return buffImg;
    }

    public String getCode() {
    
        return code.toLowerCase();
    }
}

friends , This is a very useful tool class for creating verification code , It can be reused in the future .

③ stay dao Package under the new UserDao class

@Mapper
public interface UserDao {
    
    //  Registered users 
    void save(User user);
    //  Query user by user name 
    User findByUsername(String username);
}

reminder : there @Mapper Don't forget to add , Its function is to mapper This DAO hand Spring management .

④ stay mapper New under the directory userDao.xml

 Insert picture description here

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.uos.travels.dao.UserDao">
    <!-- Save the user -->
    <insert id="save" parameterType="User" useGeneratedKeys="true" keyProperty="id">
        insert into t_user values (#{id},#{username},#{password},#{email})
    </insert>

    <!-- Query user by user name -->
    <select id="findByUsername" resultType="User" parameterType="String">
        select * from t_user where username=#{username}
    </select>
</mapper>

⑤ stay service Package under the new UserService Interface

public interface UserService {
    
    //  register 
    void register(User user);
    //  Sign in 
    User login(User user);
}

⑥ stay service Package created under impl package , And new UserServiceImpl class

@Service
@Transactional
public class UserServiceImpl implements UserService {
    

    @Autowired
    private UserDao userDao;
    @Override
    public void register(User user) {
    
        if (userDao.findByUsername(user.getUsername())==null) {
    
            userDao.save(user);
        }else {
    
            throw new RuntimeException(" User name already exists ");
        }
    }

    @Override
    public User login(User user) {
    
        User userDB = userDao.findByUsername(user.getUsername());
        if (userDB!=null) {
    
            if (user.getPassword().equals(userDB.getPassword())) {
    
                return userDB;
            }
            throw new RuntimeException(" Wrong password ");
        }else {
    
            throw new RuntimeException(" User name error ");
        }
    }
}

⑦ stay controller Package under the new UserController class

@RestController
@RequestMapping("/user")
@CrossOrigin    //  Allow cross-domain 
@Slf4j
public class UserController {
    

    @Autowired
    private UserService userService;

    /** *  register  */
    @PostMapping("/register")
    public Result register(String code, String key, @RequestBody User user, HttpServletRequest request) {
    
        Result result = new Result();

        log.info(" The received code:"+code);
        log.info(" The received user:"+user);
        String keyCode = (String) request.getServletContext().getAttribute(key);
        log.info(" The received key:"+keyCode);
        try {
    
            if (code.equalsIgnoreCase(keyCode)) {
    
                //  Registered users 
                userService.register(user);
                result.setMessage(" Registered successfully ");
                result.setState(true);
            }else {
    
                throw new RuntimeException(" Verification code error ");
            }
        }catch (Exception e) {
    
            e.printStackTrace();
            result.setMessage(e.getMessage()).setState(false);
        }
        return result;
    }

    /** *  Sign in  */
    @RequestMapping("/login")
    public Result login(@RequestBody User user,HttpServletRequest request) {
    
        Result result = new Result();
        log.info("user:"+user);

        try {
    
            User userDB = userService.login(user);
            //  Save the user's tag after successful login 
            request.getServletContext().setAttribute(userDB.getId(),userDB);
            result.setMessage(" Login successful ").setUserId(userDB.getId());
        } catch (Exception e) {
    
            e.printStackTrace();
            result.setMessage(e.getMessage()).setState(false);
        }


        return result;
    }


    /** *  Get verification code  */
    @GetMapping("/getImage")
    public Map<String, String> getImage(HttpServletRequest request) throws IOException {
    
        Map<String,String> result = new HashMap<>();
        CreateImageCode createImageCode = new CreateImageCode(120,40,4,10);
        //  Get verification code 
        String code = createImageCode.getCode();
        //  Store the verification code in session
        /*session.setAttribute("imageCode",code);*/
        String key = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        request.getServletContext().setAttribute(key,code);
        //  Generate pictures 
        BufferedImage img = createImageCode.getBuffImg();
       //  Conduct base64 code 
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ImageIO.write(img,"png",bos);
        String string = Base64Utils.encodeToString(bos.toByteArray());
        result.put("key",key);
        result.put("image",string);
        return result;
    }
}

Guys, pay attention , The above code contains two functions: registration and login . Let's focus on the front-end operation of user registration and login .

(2) User registration + The user login Front-end processing

① User registration front-end processing

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="css/style.css">
    <style> form{
      width:270px; } input{
      width: 70%; background: #eee; } input:focus{
      background: #fff; } form{
      padding: 0 12px 12px; } label{
      display: block; padding-bottom:12px; } #img-vcode{
      width: 56px; height: 21px; float:right; position: relative; top:2px; left:-6px } .label-text{
      width: 30%; float: left; } </style>
</head>
<body>
<div id="app">
    <div id="wrap">
        <div id="header">
            <div style="float: right;padding-top: 24px">
                <!-- Time display area -->
                <span id="show">
                </span>
            </div>
            <h1> Tourism information management system </h1>
        </div>
        <div id="header-bar"></div>
        <div id="content" style="height: 360px">
            <img src="img/timg.jpg" style="float: right;height: 320px">
            <h2> register </h2>
            <form action="province/provincelist.html" method="post">
                <label>
                    <div class="label-text"> zhang &emsp; Number :</div>
                    <input type="text" v-model="user.username" name="username">
                </label>
                <label>
                    <div class="label-text"> The secret &emsp; code :</div>
                    <input type="password" v-model="user.password" name="password">
                </label>
                <label>
                    <div class="label-text"> Post &emsp; box :</div>
                    <input type="text" v-model="user.email" name="email">
                </label>
                <img :src="src" id="img-vcode" :key="key" @click="changeImage">
                <label>
                    <div class="label-text"> Verification Code :</div>
                    <input type="text" v-model="vcode" name="vcode" style="width: 100px">
                </label>
                <button type="button" @click="saveUserInfo"> carry   hand over </button>&emsp;
                <a href="login.html"> Go to login </a>
            </form>
        </div>
        <div id="footer">
            [email protected]
        </div>
    </div>
</div>

<script src="js/vue.js"></script>
<script src="js/axios.min.js"></script>
<script> var app = new Vue({
      el: "#app", data: {
      user: {
     }, vcode: "", src: "", key: "" }, //  register  methods: {
      saveUserInfo(){
      /*console.log(this.user);*/ console.log(" Verification Code "+this.vcode); if (!this.user.username) {
      alert(" The username cannot be empty "); } if (!this.user.password) {
      alert(" The password cannot be empty "); } if (!this.user.email) {
      alert(" The mailbox cannot be empty "); } // send out axios axios.post("http://localhost:8080/user/register?code="+this.vcode+"&key="+this.key,this.user).then((res=>{
      console.log(res.data); if (res.data.state) {
      //  Registered successfully  alert(res.data.message+", Click OK to jump to the login page "); location.href="login.html"; }else {
      alert(res.data.message); } })); }, //  Get verification code  getImage(){
      _this = this; axios.get("http://localhost:8080/user/getImage").then((res)=>{
      console.log(res.data); //  Show pictures for decoding  _this.src = "data:image/png;base64," + res.data.image; _this.key = res.data.key; }) }, //  Switch verification code  changeImage(){
      this.getImage(); } }, created(){
      //  Get verification code  this.getImage(); } }) </script>
<script src="js/date.js"></script>
</body>
</html>

② User login front-end processing

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="css/style.css">
    <style> form{
      width:270px; } input{
      width: 70%; background: #eee; } input:focus{
      background: #fff; } form{
      padding: 0 12px 12px; } label{
      display: block; padding-bottom:12px; } #img-vcode{
      width: 56px; height: 21px; float:right; position: relative; top:2px; left:-6px } .label-text{
      width: 30%; float: left; } </style>
</head>
<body>
<div id="app">
    <div id="wrap">
        <div id="header">
            <div style="float: right;padding-top: 24px">
                <!-- Time display area -->
                <span id="show">
                </span>
            </div>
            <h1> Tourism information management system </h1>
        </div>
        <div id="header-bar"></div>
        <div id="content" style="height: 360px">
            <img src="img/timg.jpg" style="float: right;height: 320px">
            <h2> Sign in </h2>
            <form action="province/provincelist.html" method="post">
                <label>
                    <div class="label-text"> zhang &emsp; Number :</div>
                    <input type="text" name="username" v-model="user.username">
                </label>
                <label>
                    <div class="label-text"> The secret &emsp; code :</div>
                    <input type="password" name="password" v-model="user.password">
                </label>
                <!--<img src="img/vcode.png" id="img-vcode"> <label> <div class="label-text"> Verification Code :</div> <input type="text" name="vcode" style="width: 100px"> </label>-->
                <button type="button" @click="login"> carry   hand over </button>&emsp;
                <a href="reg.html"> To register </a>
            </form>
        </div>
        <div id="footer">
            [email protected]
        </div>
    </div>
</div>
    <script src="js/vue.js"></script>
    <script src="js/axios.min.js"></script>
    <script> var app = new Vue({
      el: "#app", data:{
      user:{
     }, }, methods:{
      //  Sign in  login(){
      //  send out axios axios.post("http://localhost:8080/user/login",this.user).then((res)=>{
      console.log(res.data); localStorage.setItem("userId",res.data.userId); if (res.data.state) {
      //  Login successful  alert(res.data.message+", Click OK to enter the home page "); location.href="province/provincelist.html"; }else {
      alert(res.data.message); } }); } } }) </script>
<script src="js/date.js"></script>
</body>
</html>

(3) User registration and user login effect demonstration

 Insert picture description here
The verification code in the registration can be switched by clicking ( Verification code is not case sensitive )!

3、 Provincial module development

(1) stay entity Package under the new Province Entity class

@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Province {
    
    private String id;
    private String name;
    private String tags;
    private Integer placeCounts;
}

(2) stay dao Package under the new ProvinceDao Interface

public interface BaseDao<T,K> {
    
    void save(T t);

    void delete(K k);

    void update(T t);

    T findOne(K k);

    List<T> findAll();

    List<T> findByPage(@Param("start") Integer start, @Param("rows") Integer rows);

    Integer findTotals();
    
}
@Mapper
public interface ProvinceDao extends BaseDao<Province,String> {
    
}

(3) stay mapper Under the new provinceDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.uos.travels.dao.ProvinceDao">


    <!-- Query all -->
    <select id="findByPage" resultType="Province">
        select * from t_province order by placecounts limit #{start},#{rows}
    </select>

    <!-- Total number of queries -->
    <select id="findTotals" resultType="integer">
        select count(id) from t_province
    </select>

    <!-- Province addition -->
    <insert id="save" parameterType="Province" useGeneratedKeys="true" keyProperty="id">
        insert into t_province values(#{id},#{name},#{tags},#{placeCounts})
    </insert>

    <!-- Province delete -->
    <delete id="delete" parameterType="String">
        delete from t_province where id = #{id}
    </delete>

    <!-- Query a province -->
    <select id="findOne" resultType="Province">
        select * from t_province where id = #{id}
    </select>

    <!-- Modify the province information -->
    <update id="update" parameterType="Province">
        update t_province set name=#{name},tags=#{tags},placeCounts=#{placeCounts} where id=#{id}
    </update>
</mapper>

(4) stay service Package under the new ProvinceService Interface

public interface ProvinceService {
    
    /** *start: The current page  * counts: Number of entries per page  */
    List<Province> findByPage(Integer page,Integer rows);

    /** *  Total number of queries  */
    Integer findTotals();

    /** *  Save province  */
    void save(Province province);

    /** *  Delete Province  */
    void delete(String id);

    /** *  Query Province Information  */
    Province findOne(String id);

    /** *  Update Province Information  */
    void update(Province province);
}
@Service
@Transactional
public class ProvinceServiceImpl implements ProvinceService {
    

    @Autowired
    private ProvinceDao provinceDao;

    @Override
    public List<Province> findByPage(Integer page, Integer rows) {
    
        int start = (page - 1)*rows;
        return provinceDao.findByPage(start,rows);
    }

    @Override
    public Integer findTotals() {
    
        return provinceDao.findTotals();
    }

    @Override
    public void save(Province province) {
    
        province.setPlaceCounts(0);
        provinceDao.save(province);
    }

    @Override
    public void delete(String id) {
    
        provinceDao.delete(id);
    }

    @Override
    public Province findOne(String id) {
    
        return provinceDao.findOne(id);
    }

    @Override
    public void update(Province province) {
    
        provinceDao.update(province);
    }
}

(5) stay controller Package under the new ProvinceController

@RestController
@CrossOrigin    //  Allow cross-domain 
@RequestMapping("/province")
public class ProvinceController {
    

    @Autowired
    private ProvinceService provinceService;

    /** *  Query all  */
    @RequestMapping(value = "/findByPage",method = RequestMethod.GET)
    public Map<String,Object> findByPage(Integer page,Integer rows){
    
        //  If empty, specify the default value 
        page = page==null?1:page;
        rows = rows==null?4:rows;

        Map<String, Object> map = new HashMap<>();
        //  Paging 
        List<Province> provinces = provinceService.findByPage(page, rows);
        //  Calculate the total number of pages 
        Integer totals = provinceService.findTotals();
        Integer totalPage = totals%rows==0?totals/rows:totals/rows+1;
        map.put("provinces",provinces);
        map.put("totals",totals);
        map.put("totalPage",totalPage);
        map.put("page",page);
        return map;
    }

    /** *  Add Province Information  */
    @PostMapping("/save")
    public Result save(@RequestBody Province province) {
    
        Result result = new Result();
        try {
    
            provinceService.save(province);
            result.setMessage(" Save province information successfully ");
        } catch (Exception e) {
    
            e.printStackTrace();
            result.setMessage(" Failed to save province information ").setState(false);
        }
        return result;
    }
    /** *  Delete the province information  */
    @GetMapping("/delete")
    public Result delete(String id) {
    
        Result result = new Result();
        try {
    
            provinceService.delete(id);
            result.setMessage(" Province information deleted successfully ");
        } catch (Exception e) {
    
            e.printStackTrace();
            result.setMessage(" Failed to delete Province Information ").setState(false);
        }
        return result;
    }

    /** *  Query a province  */
    @GetMapping("/findOne")
    public Province findOne(String id) {
    
        return provinceService.findOne(id);
    }

    /** *  Modify the province information  */
    @PostMapping("/update")
    public Result update(@RequestBody Province province) {
    
        Result result = new Result();
        try {
    
            provinceService.update(province);
            result.setMessage(" Province information modified successfully ");

        } catch (Exception e) {
    
            e.printStackTrace();
            result.setState(false).setMessage(e.getMessage());
        }
        return result;
    }
}

(6) Front page

Add province page

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="../css/style.css">
    <style> form{
      width:270px; } input{
      width: 70%; background: #eee; } input:focus{
      background: #fff; } form{
      padding: 0 12px 12px; } label{
      display: block; padding-bottom:12px; } .label-text{
      width: 30%; float: left; } </style>
</head>
<body>
<div id="app">
    <div id="wrap">
        <div id="header">
            <div style="float: right;padding-top: 24px">
                <!-- Time display area -->
                <span id="show">
                </span></div>
                <h1> Tourism information management system </h1>
        </div>
        <div id="header-bar"></div>
        <div id="content" style="height: 360px">
            <img src="../img/timg.jpg" style="float: right;height: 320px">
            <h2> Add provinces </h2>
            <form action="provincelist.html" method="post">
                <label>
                    <div class="label-text"> province &emsp; Share :</div>
                    <input type="text" v-model="province.name">
                </label>
                <label>
                    <div class="label-text" > mark &emsp; sign :</div>
                    <input type="text" v-model="province.tags">
                </label>
                <button type="button" @click="saveProvinceInfo"> carry   hand over </button>&emsp;
                <a href="provincelist.html"> return </a>
            </form>
        </div>
        <div id="footer">
            [email protected]
        </div>
    </div>
</div>
    <script src="../js/vue.js"></script>
    <script src="../js/axios.min.js"></script>
    <script> var app = new Vue({
      el: "#app", data:{
      province:{
     }, }, methods:{
      //  Save province information  saveProvinceInfo(){
      /* if (!this.province.name) { alert(" Province name cannot be empty "); } if (!this.province.tags) { alert(" The province label cannot be empty "); }*/ //  send out axios axios.post("http://localhost:8080/province/save",this.province).then((res)=>{
      console.log(res.data); if (res.data.state) {
      //  Save province information successfully  alert(res.data.message+", Click OK to jump to the province list page "); location.href="provincelist.html"; }else {
      alert(res.data.message); } }); } } }) </script>
<script src="../js/date.js"></script>
</body>
</html>

Page list of provinces

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="../css/style.css">
    <style> table{
      width: 100%; margin-bottom: 15px; border-collapse: collapse; table-layout: fixed; } th,td{
      border: 1px solid #CBD6DE; padding-left: 10px; line-height: 28px; } th{
      text-align: center; background: linear-gradient(#edf2f5,#dce9f2,#edf2f5); color:#467aa7; } tbody tr:nth-child(even){
      background: #f2f2f2; } #pages{
      text-align: center; padding-top: 8px; } .page{
      min-width: 50px; display: inline-block; } </style>
    <script src="../js/date.js"></script>
</head>
<body>
<div id="app">
<div id="wrap">
    <div id="header">
        <div style="float: right;padding-top: 24px">
            <!-- Time display area -->
            <span id="show">
            </span>
            <a href="../login.html" style="color:#fff;float: right"> Safety exit </a>
        </div>
        <h1> Tourism information management system </h1>
    </div>
    <div id="header-bar"></div>
    <div id="content" style="height: 360px">
        <h2> List of provinces </h2>
        <table>
            <thead>
                <tr>
                    <th width="15%">ID</th>
                    <th width="20%"> Province </th>
                    <th width="25%"> label </th>
                    <th width="15%"> Number of scenic spots </th>
                    <th width="25%"> operation </th>
                </tr>
            </thead>
            <tbody>
            <tr v-for="province in provinces" :key="province.id" align="center">
                <td v-text="province.id"></td>
                <td v-text="province.name"></td>
                <td v-text="province.tags"></td>
                <td v-text="province.placeCounts"></td>
                <td>
                    <a href="javascript:;" @click="deleteProvince(province.id)"> Delete Province </a>
                    <a :href="'../viewspot/viewspotlist.html?id='+province.id"> List of attractions </a>
                    <a :href="'./updateprovince.html?id='+province.id"> Modify Province </a>
                </td>
            </tr>
            </tbody>
        </table>
        <a href="addprovince.html">
            <button type="button"> Add provinces </button>
        </a>
        <div id="pages">
            <a href="javascript:;" class="page" @click="findAll(page-1)" v-if="page>1">&lt; The previous page </a>
            <a href="javascript:;" class="page" @click="findAll(page-1)" v-if="page==1" disabled="">&lt; The previous page </a>
            <a href="javascript:;" class="page" v-for="indexpage in totalPage" v-text="indexpage" @click="findAll(indexpage)"></a>
            <a href="javascript:;" class="page" v-if="page==totalPage"> The next page &gt;</a>
            <a href="javascript:;" class="page" v-if="page!=totalPage" @click="findAll(page+1)"> The next page &gt;</a>
        </div>
    </div>
    <div id="footer">
        [email protected]
    </div>
</div>
</div>

<script src="../js/vue.js"></script>
<script src="../js/axios.min.js"></script>
<script> var app = new Vue({
      el: "#app", data:{
      provinces:[], page:1, rows:4, totalPage:0, totals:0, id:0 }, methods:{
      //  Query all  findAll(indexpage){
      if (indexpage){
      this.page=indexpage; } _this = this; //  send out axios axios.get("http://localhost:8080/province/findByPage?page="+this.page).then((res)=>{
      _this.provinces = res.data.provinces; _this.page = res.data.page; _this.rows = res.data.rows; _this.totalPage = res.data.totalPage; _this.totals = res.data.totals; }); }, //  Delete Province Information  deleteProvince(id){
      if (confirm(" Are you sure you want to delete the province information ?")){
      axios.get("http://localhost:8080/province/delete?id="+id).then((res)=>{
      if (res.data.state) {
      //  Province information deleted successfully  alert(res.data.message+", Click OK to jump to the province list page "); //  Refresh current page  location.reload(true); }else {
      alert(res.data.message); } }) } } }, created(){
      this.findAll(); } }) </script>
<script src="../js/date.js"></script>
</body>
</html>

Update the province list page

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="../css/style.css">
    <style> form{
      width:270px; } input{
      width: 70%; background: #eee; } input:focus{
      background: #fff; } form{
      padding: 0 12px 12px; } label{
      display: block; padding-bottom:12px; } .label-text{
      width: 30%; float: left; } </style>
</head>
<body>
<div id="app">
    <div id="wrap">
        <div id="header">
            <div style="float: right;padding-top: 24px">
                <!-- Time display area -->
                <span id="show">
                </span>
            </div>
            <h1> Tourism information management system </h1>
        </div>
        <div id="header-bar"></div>
        <div id="content" style="height: 360px">
            <img src="../img/timg.jpg" style="float: right;height: 320px">
            <h2> Modify Province </h2>
            <form action="provincelist.html" method="post">
                <label>
                    <div class="label-text"> province &emsp; Share :</div>
                    <input type="text" v-model="province.name">
                </label>
                <label>
                    <div class="label-text"> mark &emsp; sign :</div>
                    <input type="text" v-model="province.tags">
                </label>
                <button type="button" @click="updateProvince"> carry   hand over </button>&emsp;
                <a href="provincelist.html"> return </a>
            </form>
        </div>
        <div id="footer">
            [email protected]
        </div>
    </div>
</div>
    <script src="../js/vue.js"></script>
    <script src="../js/axios.min.js"></script>
    <script> var app = new Vue({
      el: "#app", data:{
      id:"", province:{
     } }, methods:{
      findOneProvince(id){
      _this = this; axios.get("http://localhost:8080/province/findOne?id="+id).then((res)=>{
      console.log(res.data); _this.province = res.data; }); }, updateProvince() {
      axios.post("http://localhost:8080/province/update",this.province).then((res)=>{
      if (res.data.state) {
      //  Province information modified successfully  alert(res.data.message+", Click OK to jump to the province list page "); location.href="provincelist.html"; }else {
      alert(res.data.message); } }); } }, created(){
      this.id = location.href.substring(location.href.indexOf("=")+1); this.findOneProvince(this.id); } }) </script>
<script src="../js/date.js"></script>
</body>
</html>

(7) Effect demonstration

 Insert picture description here

4、 Scenic spot module development

(1) establish Place Entity class

package com.uos.travels.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.Date;

/** * @author  Your royal highness  * @date 2020/6/1 18:49 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Place {
    
    private String id;
    private String name;
    private String picPath;
    @JsonFormat(pattern = "yyyy/MM/dd")
    private Date hotTime;
    private Double hotTicket;
    private Double dimTicket;
    private String placeDes;
    private String provinceId;
}

(2) establish PlaceDao Interface

@Mapper
public interface PlaceDao extends BaseDao<Place,String> {
    

    /** *  Paging query  */
    List<Place> findByProvinceIdPage(@Param("start") Integer start, @Param("rows") Integer rows,@Param("provinceId") String provinceId);

    /** *  according to id Query the number of provinces  */
    Integer findByProvinceIdCounts(String id);

    /** * Save attraction information  */
    void save(Place place);
    
}

(3) To write placeDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.uos.travels.dao.PlaceDao">

    <!-- According to province id Query all attractions and sort -->
    <select id="findByProvinceIdPage" resultType="Place">
        select * from t_place where provinceid = #{provinceId} order by hotticket limit #{start},#{rows}
    </select>

    <!-- According to province id Query the number of scenic spots in the current province -->
    <select id="findByProvinceIdCounts" resultType="Integer" parameterType="String">
        select count(id) from t_place where provinceid = #{provinceId}
    </select>

    <!-- Save attraction information -->
    <insert id="save" parameterType="Place" useGeneratedKeys="true" keyProperty="id">
        insert into t_place values(#{id},#{name},#{picPath},#{hotTime},#{hotTicket},#{dimTicket},#{placeDes},#{provinceId})
    </insert>

    <!-- according to id Query the scenic spot information -->
    <select id="findOne" parameterType="String" resultType="Place">
        select * from t_place where id = #{id}
    </select>

    <!-- according to id Delete scenic spot information -->
    <delete id="delete" parameterType="String">
        delete from t_place where id = #{id}
    </delete>

    <!-- Modify scenic spot information -->
    <update id="update" parameterType="Place">
        update t_place set
            name = #{name},
            picpath = #{picPath},
            hottime = #{hotTime},
            hotticket = #{hotTicket},
            dimticket = #{dimTicket},
            placedes = #{placeDes},
            provinceid = #{provinceId}
        where id = #{id}
    </update>

</mapper>

(4) To write PlaceService Interface

public interface PlaceService {
    
    List<Place> findByProvinceIdPage(Integer page, Integer rows, String provinceId);

    Integer findByProvinceIdCounts(String id);

    void save(Place place);

    void delete(String id);

    void update(Place place);

    Place findOne(String id);
}
@Service
@Transactional
public class PlaceServiceImpl implements PlaceService {
    

    @Autowired
    private PlaceDao placeDao;
    
    @Autowired
    private ProvinceService provinceService;

    @Override
    public List<Place> findByProvinceIdPage(Integer page, Integer rows, String provinceId) {
    
        int start = (page - 1)*rows;
        return placeDao.findByProvinceIdPage(start,rows,provinceId);
    }

    @Override
    public Integer findByProvinceIdCounts(String id) {
    
        return placeDao.findByProvinceIdCounts(id);
    }

    @Override
    public void save(Place place) {
    
        placeDao.save(place);
        //  Query Province Information 
        Province province = provinceService.findOne(place.getProvinceId());
        //  Update several scenic spots in provinces 
        province.setPlaceCounts(province.getPlaceCounts()+1);
        provinceService.update(province);
    }

    @Override
    public void delete(String id) {
    
        Place place = placeDao.findOne(id);
        Province province = provinceService.findOne(place.getProvinceId());
        province.setPlaceCounts(province.getPlaceCounts()-1);
        //  Update scenic spot information , Reduce the number of scenic spots in the current province 1
        provinceService.update(province);
        //  Delete scenic spot information 
        placeDao.delete(id);
    }

    @Override
    public void update(Place place) {
    
        placeDao.update(place);
    }

    @Override
    public Place findOne(String id) {
    
        return placeDao.findOne(id);
    }
}

(5) To write PlaceController class

@RestController
@CrossOrigin    //  Allow cross-domain 
@RequestMapping("/place")
public class PlaceController {
    

    @Autowired
    private PlaceService placeService;

    @Value("${upload.dir}")
    private String realPath;

    /** *  Query all  */
    @GetMapping(value = "/findAllPage")
    public Map<String,Object> findAllPage(Integer page, Integer rows,String provinceId){
    
        //  If empty, specify the default value 
        page = page==null?1:page;
        rows = rows==null?3:rows;

        Map<String, Object> result = new HashMap<>();
        //  Collection of scenic spots 
        List<Place> places = placeService.findByProvinceIdPage(page,rows,provinceId);
        //  Process paging 
        Integer counts = placeService.findByProvinceIdCounts(provinceId);
        //  Total number of pages 
        Integer totalPage = counts%rows==0?counts/rows:counts/rows+1;

        result.put("places",places);
        result.put("counts",counts);
        result.put("totalPage",totalPage);
        result.put("page",page);

        return result;
    }

    /** *  Save attraction information  */
    @PostMapping("/save")
    public Result save(MultipartFile pic, Place place) throws IOException {
    
        /*System.out.println(pic.getOriginalFilename());*/
        System.out.println(place);
        Result result = new Result();
        try {
    
            //  File upload processing 
            String extension = FilenameUtils.getExtension(pic.getOriginalFilename());
            String newFileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + extension;
            // bas464 Encoding processing 
            place.setPicPath(Base64Utils.encodeToString(pic.getBytes()));
            pic.transferTo(new File(realPath,newFileName));
            //  Save the attraction object 
            placeService.save(place);
            result.setMessage(" Successfully saved scenic spot information ");
        } catch (Exception e) {
    
            result.setState(false).setMessage(e.getMessage());
        }
        return result;
    }
    /** *  Delete scenic spot information  */
    @GetMapping("/delete")
    public Result delete(String id){
    
        Result result = new Result();
        try {
    
            placeService.delete(id);
            result.setMessage(" Successfully deleted scenic spot information ");
        } catch (Exception e) {
    
            e.printStackTrace();
            result.setState(false).setMessage(e.getMessage());
        }
        return result;
    }
    /** *  Query the scenic spot information  */
    @GetMapping("/findOne")
    public Place findOne(String id){
    
        return placeService.findOne(id);
    }
    /** *  Update scenic spot information  */
    @PostMapping("/update")
    public Result update(MultipartFile pic,Place place) throws IOException {
    
        Result result = new Result();
        try {
    
            //  Do... On the picture base64 Handle 
            String picPath = Base64Utils.encodeToString(pic.getBytes());
            place.setPicPath(picPath);

            //  File upload processing 
            String extension = FilenameUtils.getExtension(pic.getOriginalFilename());
            String newFileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + extension;
            pic.transferTo(new File(realPath,newFileName));
            // Modify scenic spot information 
            placeService.update(place);
            result.setMessage(" Successfully modified the scenic spot information ");
        } catch (Exception e) {
    
            e.printStackTrace();
            result.setState(false).setMessage(e.getMessage());
        }

        return result;
    }
}

(6) Front page

Add attractions page

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="../css/style.css">
    <style> form{
      width:270px; } input{
      width: 64%; background: #eee; } input:focus{
      background: #fff; } form{
      padding: 0 12px 12px; } label{
      display: block; padding-bottom:12px; } .label-text{
      width: 36%; float: left; } #upload-tip{
      border: 1px dashed #d9d9d9; width: 135px; height: 135px; line-height: 135px; cursor: pointer; font-size: 36px; color:#d9d9d9; } #img-show{
      width: 135px; height: 135px; display: block; margin: 0 auto; object-fit: cover; } </style>
    <script> function imgfileChange() {
      var upload_tip = document.getElementById("upload-tip"); var img_show = document.getElementById("img-show"); var imgfile = document.getElementById("imgfile"); var freader = new FileReader(); freader.readAsDataURL(imgfile.files[0]); freader.onload = function (e) {
      img_show.src = e.target.result; img_show.style.display = "inline"; upload_tip.style.display = "none"; }; } </script>
</head>
<body>
<div id="app">
    <div id="wrap">
        <div id="header">
            <div style="float: right;padding-top: 24px">
                <!-- Time display area -->
                <span id="show">
                </span>
            </div>
            <h1> Tourism information management system </h1>
        </div>
        <div id="header-bar"></div>
        <div id="content" style="height: 480px">
            <img src="../img/timg.jpg" style="float: right;height: 320px">
            <h2> Add attractions </h2>
            <form action="viewspotlist.html" method="post">
                <label>
                    <div class="label-text"> view &emsp;&emsp; spot :</div>
                    <input type="text" v-model="place.name">
                </label>
                <label>
                    <div class="label-text"> Impression picture :</div>
                    <div style="text-align: center;padding-left: 36%">
                        <div id="upload-tip">+</div>
                        <img src="" alt="" id="img-show" style="display: none">
                        <input type="file" id="imgfile" ref="myFile" style="display: none" onchange="imgfileChange()">
                    </div>
                </label>
                <label>
                    <div class="label-text"> Peak Season :</div>
                    <input type="text" v-model="place.hotTime">
                </label>
                <label>
                    <div class="label-text"> Peak season tickets :</div>
                    <input type="text" v-model="place.hotTicket">
                </label>
                <label>
                    <div class="label-text"> Off season tickets :</div>
                    <input type="text" v-model="place.dimTicket">
                </label>
                <label>
                    <div class="label-text"> Scenic spot description :</div>
                    <input type="text" v-model="place.placeDes">
                </label>
                <label>
                    <div class="label-text"> Province :</div>
                    <select v-model="place.provinceId">
                        <option :value="pro.id" v-for="pro in provinces" v-text="pro.name"></option>
                    </select>
                </label>
                <button type="button" @click="savePlaceInfo"> carry   hand over </button>&emsp;
                <a :href="'./viewspotlist.html?id='+id"> return </a>
            </form>
        </div>
        <div id="footer">
            [email protected]
        </div>
    </div>
</div>

    <script src="../js/vue.js"></script>
    <script src="../js/axios.min.js"></script>
    <script> var app = new Vue({
      el: "#app", data:{
      provinces:[], place:{
     }, id:"", }, methods:{
      findAllProvinces(){
      // Check all attractions  _this = this; axios.get("http://localhost:8080/province/findByPage?rows=35").then((res)=>{
      console.log(res.data.provinces); _this.provinces = res.data.provinces; }) }, savePlaceInfo() {
      // Save all attractions  console.log(this.place); let myFile = this.$refs.myFile; let files = myFile.files; let file = files[0]; let formData = new FormData(); formData.append('pic',file); formData.append('name',this.place.name); formData.append('hotTime',this.place.hotTime); formData.append('hotTicket',this.place.hotTicket); formData.append('dimTicket',this.place.dimTicket); formData.append('placeDes',this.place.placeDes); formData.append('provinceId',this.place.provinceId); // send out axios request  axios({
      method:'post', url:'http://localhost:8080/place/save', data:formData, headers:{
      'Content-Type':'multipart/form-data' } }).then((res)=>{
      console.log(res.data); if (res.data.state) {
      alert(res.data.message+", Click OK to jump to the list of scenic spots "); location.href = "./viewspotlist.html?id=" + this.place.provinceId; }else {
      alert(res.data.message); } }) } }, created(){
      this.findAllProvinces(); let id = location.href.substring(location.href.indexOf("=")+1); this.id = id; } }) </script>
<script src="../js/date.js"></script>
</body>
</html>

Update the attractions page

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="../css/style.css">
    <style> form{
      width:270px; } input{
      width: 64%; background: #eee; } input:focus{
      background: #fff; } form{
      padding: 0 12px 12px; } label{
      display: block; padding-bottom:12px; } .label-text{
      width: 36%; float: left; } #img-show{
      width: 135px; height: 135px; display: block; margin: 0 auto; object-fit: cover; } </style>
    <script> function imgfileChange() {
      var img_show = document.getElementById("img-show"); var imgfile = document.getElementById("imgfile"); var freader = new FileReader(); freader.readAsDataURL(imgfile.files[0]); freader.onload = function (e) {
      img_show.src = e.target.result; }; } </script>
</head>
<body>
<div id="app">
    <div id="wrap">
        <div id="header">
            <div style="float: right;padding-top: 24px">
                <!-- Time display area -->
                <span id="show">
                </span>
            </div>
            <h1> Tourism information management system </h1>
        </div>
        <div id="header-bar"></div>
        <div id="content" style="height: 480px">
            <img src="../img/timg.jpg" style="float: right;height: 320px">
            <h2> Modify the scenic spot </h2>
            <form action="viewspotlist.html" method="post">
                <label>
                    <div class="label-text"> view &emsp;&emsp; spot :</div>
                    <input type="text" v-model="place.name">
                </label>
                <label>
                    <div class="label-text"> Impression picture :</div>
                    <div style="text-align: center;padding-left: 36%">
                        <img :src="src" alt="" id="img-show">
                        <input type="file" id="imgfile" ref="myFile" style="display: none" onchange="imgfileChange()">
                    </div>
                </label>
                <label>
                    <div class="label-text"> Peak Season :</div>
                    <input type="text" v-model="place.hotTime">
                </label>
                <label>
                    <div class="label-text"> Peak season tickets :</div>
                    <input type="text" v-model="place.hotTicket">
                </label>
                <label>
                    <div class="label-text"> Off season tickets :</div>
                    <input type="text" v-model="place.dimTicket">
                </label>
                <label>
                    <div class="label-text"> Scenic spot description :</div>
                    <input type="text" v-model="place.placeDes">
                </label>
                <label>
                    <div class="label-text"> Province :</div>
                    <select v-model="place.provinceId">
                        <option :value="pro.id" v-for="pro in provinces" v-text="pro.name"></option>
                    </select>
                </label>
                <button type="button" @click="updatePlace"> carry   hand over </button>&emsp;
                <a :href="'viewspotlist.html?id='+place.provinceId"> return </a>
            </form>
        </div>
        <div id="footer">
            [email protected]
        </div>
    </div>
</div>

    <script src="../js/vue.js"></script>
    <script src="../js/axios.min.js"></script>
    <script> var app = new Vue({
      el: "#app", data:{
      id:"", place:{
     }, src:"", provinces:[] }, methods:{
      findOnePlace(){
      _this = this; axios.get("http://localhost:8080/place/findOne?id="+this.id).then((res)=>{
      _this.place = res.data; _this.src = 'data:image/jpg;base64,'+res.data.picPath; }) }, findAllProvinces(){
      // Check all attractions  _this = this; axios.get("http://localhost:8080/province/findByPage?rows=35").then((res)=>{
      console.log(res.data.provinces); _this.provinces = res.data.provinces; }) }, updatePlace(){
      console.log(this.place); let myFile = this.$refs.myFile; let files = myFile.files; let file = files[0]; let formData = new FormData(); formData.append('pic',file); formData.append('id',this.place.id); formData.append('name',this.place.name); formData.append('hotTime',this.place.hotTime); formData.append('hotTicket',this.place.hotTicket); formData.append('dimTicket',this.place.dimTicket); formData.append('placeDes',this.place.placeDes); formData.append('provinceId',this.place.provinceId); // send out axios request  axios({
      method:'post', url:'http://localhost:8080/place/update', data:formData, headers:{
      'Content-Type':'multipart/form-data' } }).then((res)=>{
      console.log(res.data); if (res.data.state) {
      alert(res.data.message+", Click OK to jump to the list of scenic spots "); location.href = "./viewspotlist.html?id=" + this.place.provinceId; }else {
      alert(res.data.message); } }) } }, created(){
      let id = location.href.substring(location.href.indexOf("=")+1); this.id = id; this.findOnePlace(); this.findAllProvinces(); } }) </script>

<script src="../js/date.js"></script>
</body>
</html>

Scenic spot list page

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="../css/style.css">
    <style> table{
      width: 100%; margin-bottom: 15px; border-collapse: collapse; table-layout: fixed; } th,td{
      border: 1px solid #CBD6DE; padding-left: 10px; line-height: 28px; } th{
      text-align: center; background: linear-gradient(#edf2f5,#dce9f2,#edf2f5); color:#467aa7; } tbody tr:nth-child(4n),tbody tr:nth-child(4n-1){
      background: #f2f2f2; } #pages{
      text-align: center; padding: 8px 0; } .page{
      min-width: 50px; display: inline-block; } .viewspotimg{
      width: 135px; height: 135px; margin-left: -10px; display: block; object-fit: cover; } </style>
</head>
<body>
<div id="app">
    <div id="wrap">
        <div id="header">
            <div style="float: right;padding-top: 24px">
                <!-- Time display area -->
                <span id="show">
                </span>
                <a href="../login.html" style="color:#fff;float: right"> Safety exit </a>
            </div>
            <h1> Tourism information management system </h1>
        </div>
        <div id="header-bar"></div>
        <div id="content">
            <h2> List of attractions </h2>
            <table>
                <thead>
                <tr >
                    <th width="14%">ID</th>
                    <th width="20%"> Scenic spot </th>
                    <th width="12%"> Impression map </th>
                    <th width="16%"> Peak Season </th>
                    <th width="10%"> Peak season tickets </th>
                    <th width="10%"> Off season tickets </th>
                    <th width="18%"> operation </th>
                </tr>
                </thead>
                <tbody v-for="place in places">
                    <tr align="center">
                        <td rowspan="2"><span v-text="place.id"></span></td>
                        <td rowspan="2"><span v-text="place.name"></span></td>
                        <td><img :src="'data:image/jpg;base64,'+place.picPath" class="viewspotimg"></td>
                        <td><span v-text="place.hotTime"></span></td>
                        <td><span v-text="place.hotTicket"></span></td>
                        <td><span v-text="place.dimTicket"></span></td>
                        <td style="text-align: center">
                            <a href="javascript:;" @click="deletePlace(place.id)"> Delete attractions </a><br>
                            <a :href="'updateviewspot.html?id='+place.id"> Modify the scenic spot </a>
                        </td>
                    </tr>
                    <tr>
                        <td colspan="5">
                            <div style="height: 56px;font-size: 14px;line-height: normal">
                                <b style="color:#467aa7"> brief introduction :</b> <span v-text="place.placeDes"></span>
                            </div>
                        </td>
                    </tr>
                </tbody>
            </table>
            <a :href="'./addviewspot.html?id='+id"><button type="button"> Add attractions </button></a>&emsp;
            <a href="../province/provincelist.html"> Return to the list of provinces </a>
            <div id="pages">
                <a href="javascript:;" v-if="page!=1" class="page" @click="findAllPage(page-1)">&lt; The previous page </a>
                <a href="javascript:;" class="page" v-if="page==1">&lt; The previous page </a>
                <span v-for="index in totalPage">
                    <a href="javascript:;" class="page" v-if="page==index" v-text="index"></a>
                    <a href="javascript:;" class="page" v-if="page!=index" v-text="index" @click="findAllPage(index)"></a>
                </span>
                <a href="javascript:;" v-if="page<totalPage" class="page" @click="findAllPage(page+1)"> The next page &gt;</a>
                <a href="javascript:;" v-if="page==totalPage" class="page"> The next page &gt;</a>
            </div>
        </div>
        <div id="footer">
            [email protected]
        </div>
    </div>
</div>

<script src="../js/vue.js"></script>
<script src="../js/axios.min.js"></script>
<script> var app = new Vue({
      el: "#app", data:{
      places:[], id:"", totalPage:0, page:1, }, methods:{
      findAllPage(index){
      //  Encapsulated into a function that queries all  _this = this; if (index) {
      this.page = index; } axios.get("http://localhost:8080/place/findAllPage?provinceId="+this.id+'&page='+this.page).then((res)=>{
      _this.places = res.data.places; _this.totalPage = res.data.totalPage; _this.page = res.data.page; }) }, deletePlace(id){
      // Delete scenic spot information  _this = this; console.log(id); if (confirm(' Are you sure you want to delete the attraction ?')) {
      axios.get("http://localhost:8080/place/delete?id="+id).then((res)=>{
      if (res.data.state) {
      //  Successfully deleted scenic spot information  alert(res.data.message+", Click OK to refresh the page "); //  Refresh current page  location.reload(true); }else {
      alert(res.data.message); } }) } }, }, created(){
      let id = location.href.substring(location.href.indexOf("=")+1); this.id = id; console.log(id); this.findAllPage(); } }) </script>
<script src="../js/date.js"></script>
</body>
</html>

(7) Effect demonstration

 Insert picture description here

Four 、 Project source download address

be based on Spring Boot+Vue Front and rear end separated tourism projects

At the end : Thank you for reading ! If you think this blog is well written , Like it + Attention !

copyright notice
author[@The road of youth],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2022/132/202205120516072760.html

Random recommended