Springboot JSP项目如何以war、jar方式运行

文章目录

  • 一,序
  • 二,样例代码
    • 1,代码结构
    • 2,完整代码备份
  • 三,准备工作
    • 1. pom.xml 引入组件
    • 2. application.yml 指定jsp配置
  • 四,war方式运行
    • 1. 修改pom.xml文件
    • 2. mvn执行打包
  • 五,jar方式运行
    • 1. 修改pom-jsp-jar.xml文件
    • 2. 修改 spring-boot-maven-plugin添加版本号
    • 3. 添加资源文件配置(`Jar运行必须`)
    • 4. mvn执行打包
  • 六,war、jar配置文件区别

一,序

Spring Boot 官方不推荐使用JSP来作为视图,但是仍有部分项目使用了JSP视图,Springboot JSP项目运行方式有war、Jar两种方式。

二,样例代码

1,代码结构

在这里插入图片描述

2,完整代码备份

如何使用下面的备份文件恢复成原始的项目代码,请移步查阅:神奇代码恢复工具

//goto Dockerfile
#基础镜像
FROM openjdk:8-jre-alpine

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone

#把你的项目war包引入到容器的root目录下
COPY target/*.war /app.war

CMD ["--server.port=8080"]

#项目的启动方式
#ENTRYPOINT ["java","-Xmx400m","-Xms400m","-Xmn150m","-Xss1024k","-jar","/app.war", "--spring.profiles.active=prod"]
ENTRYPOINT ["java","-jar","/app.war"]
//goto pom-jsp-jar.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.fly</groupId>
	<artifactId>docker-demo</artifactId>
	<version>0.0.1</version>
	<packaging>jar</packaging>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.4.RELEASE</version>
		<relativePath />
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.build.timestamp.format>yyyyMMdd-HH</maven.build.timestamp.format>
		<docker.hub>registry.cn-shanghai.aliyuncs.com</docker.hub>
		<java.version>1.8</java.version>
		<skipTests>true</skipTests>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-log4j2</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<scope>compile</scope>
		</dependency>

		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
		</dependency>
		<dependency>
			<groupId>com.google.guava</groupId>
			<artifactId>guava</artifactId>
			<version>20.0</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional>
		</dependency>

		<!-- JSTL for JSP -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
		</dependency>

		<!-- For JSP compilation -->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<scope>provided</scope>
		</dependency>
	</dependencies>

	<build>
		<finalName>${project.artifactId}-${project.version}</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<version>1.4.2.RELEASE</version>
			</plugin>

			<!-- 添加docker-maven插件 -->
			<plugin>
				<groupId>io.fabric8</groupId>
				<artifactId>docker-maven-plugin</artifactId>
				<version>0.41.0</version>
				<executions>
					<execution>
						<phase>package</phase>
						<goals>
							<goal>build</goal>
							<goal>push</goal>
							<goal>remove</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<!-- 连接到带docker环境的linux服务器编译image -->
					<!-- <dockerHost>http://192.168.182.10:2375</dockerHost> -->

					<!-- Docker 推送镜像仓库地址 -->
					<pushRegistry>${docker.hub}</pushRegistry>
					<images>
						<image>
							<!--推送到私有镜像仓库,镜像名需要添加仓库地址 -->
							<name>${docker.hub}/00fly/${project.artifactId}:${project.version}-UTC-${maven.build.timestamp}</name>
							<!--定义镜像构建行为 -->
							<build>
								<dockerFileDir>${project.basedir}</dockerFileDir>
							</build>
						</image>
						<image>
							<name>${docker.hub}/00fly/${project.artifactId}:${project.version}</name>
							<build>
								<dockerFileDir>${project.basedir}</dockerFileDir>
							</build>
						</image>
					</images>
				</configuration>
			</plugin>
		</plugins>
		<resources>
			<resource>
				<directory>src/main/java</directory>
				<excludes>
					<exclude>**/*.java</exclude>
				</excludes>
			</resource>
			<resource>
				<directory>src/main/resources</directory>
				<includes>
					<include>**/**</include>
				</includes>
			</resource>
			<resource>
				<directory>src/main/webapp</directory>
				<includes>
					<include>**/**</include>
				</includes>
				<targetPath>META-INF/resources</targetPath>
			</resource>
		</resources>
	</build>
</project>
//goto pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.fly</groupId>
	<artifactId>docker-demo</artifactId>
	<version>0.0.1</version>
	<packaging>war</packaging>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.4.RELEASE</version>
		<relativePath />
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.build.timestamp.format>yyyyMMdd-HH</maven.build.timestamp.format>
		<docker.hub>registry.cn-shanghai.aliyuncs.com</docker.hub>
		<java.version>1.8</java.version>
		<skipTests>true</skipTests>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-log4j2</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<scope>compile</scope>
		</dependency>

		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
		</dependency>
		<dependency>
			<groupId>com.google.guava</groupId>
			<artifactId>guava</artifactId>
			<version>20.0</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional>
		</dependency>

		<!-- JSTL for JSP -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
		</dependency>

		<!-- For JSP compilation -->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<scope>provided</scope>
		</dependency>
	</dependencies>

	<build>
		<finalName>${project.artifactId}-${project.version}</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>

			<!-- 添加docker-maven插件 -->
			<plugin>
				<groupId>io.fabric8</groupId>
				<artifactId>docker-maven-plugin</artifactId>
				<version>0.41.0</version>
				<executions>
					<execution>
						<phase>package</phase>
						<goals>
							<goal>build</goal>
							<goal>push</goal>
							<goal>remove</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<!-- 连接到带docker环境的linux服务器编译image -->
					<!-- <dockerHost>http://192.168.182.10:2375</dockerHost> -->

					<!-- Docker 推送镜像仓库地址 -->
					<pushRegistry>${docker.hub}</pushRegistry>
					<images>
						<image>
							<!--推送到私有镜像仓库,镜像名需要添加仓库地址 -->
							<name>${docker.hub}/00fly/${project.artifactId}:${project.version}-UTC-${maven.build.timestamp}</name>
							<!--定义镜像构建行为 -->
							<build>
								<dockerFileDir>${project.basedir}</dockerFileDir>
							</build>
						</image>
						<image>
							<name>${docker.hub}/00fly/${project.artifactId}:${project.version}</name>
							<build>
								<dockerFileDir>${project.basedir}</dockerFileDir>
							</build>
						</image>
					</images>
				</configuration>
			</plugin>
		</plugins>
		<resources>
			<resource>
				<directory>src/main/java</directory>
				<excludes>
					<exclude>**/*.java</exclude>
				</excludes>
			</resource>
			<resource>
				<directory>src/main/resources</directory>
				<includes>
					<include>**/**</include>
				</includes>
			</resource>
			<resource>
				<directory>src/main/webapp</directory>
				<includes>
					<include>**/**</include>
				</includes>
				<targetPath>META-INF/resources</targetPath>
			</resource>
		</resources>
	</build>
</project>
//goto shell\docker\1-n\docker-compose.yml
version: '3'
services:
  demo-dk:
    image: demo-dk:1.0
    build:
      context: .
      dockerfile: Dockerfile
    container_name: demo_dk
    deploy:
      resources:
        limits:
          cpus: '0.50'
          memory: 300M
        reservations:
          memory: 128M
    ports:
    - 8085:8085
    - 8086:8086
    - 8087:8087
    logging:
      driver: json-file
      options:
        max-size: 5m
        max-file: '1'
//goto shell\docker\1-n\Dockerfile
#基础镜像
FROM openjdk:8-jre-alpine

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone

#把你的项目war包引入到容器的root目录下
COPY *.war /app.war

RUN echo \
"#!/bin/sh\n"\
"nohup java -jar /app.war --server.port=8085 &\n"\
"nohup java -jar /app.war --server.port=8086 &"\
>> /start.sh

RUN chmod +x /start.sh
CMD nohup sh -c "/start.sh && java -jar /app.war --server.port=8087"
//goto shell\docker\1-n\restart-docker.sh
#!/bin/bash
docker-compose down && docker system prune -f && docker-compose build && docker-compose up -d
//goto shell\docker\1-n\start.sh
#!/bin/bash

# 命令后加入 & ,保持程序后台持续运行
nohup java -jar /app.war --server.port=8085 & 
nohup java -jar /app.war --server.port=8086 &

# 死循环,保持docker前台运行
while [[ true ]]; do
    sleep 1
done

//goto shell\docker\1-n\start2.sh
#!/bin/bash

# 命令后加入 & ,保持程序后台持续运行
nohup java -jar /app.war --server.port=8085 & 
java -jar /app.war --server.port=8086
//goto shell\docker\scale\docker-compose.yml
version: '3.8'
services:
  nginx:
    image: nginx:alpine
    container_name: nginx
    deploy:
      resources:
        limits:
          cpus: '0.80'
          memory: 50M
        reservations:
          memory: 30M
    ports:
      - 80:80
    restart: on-failure
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/conf.d:/etc/nginx/conf.d
    logging:
      driver: 'json-file'
      options:
        max-size: '5m'
        max-file: '1'  
    depends_on:
      - demo
     
  demo:
    hostname: demo
    image: registry.cn-shanghai.aliyuncs.com/00fly/docker-demo:0.0.1
    deploy:
      resources:
        limits:
          cpus: '0.80'
          memory: 200M
        reservations:
          memory: 100M
    environment:
      - JAVA_OPTS=-server -Xms128m -Xmx128m -Djava.security.egd=file:/dev/./urandom
    restart: on-failure
    logging:
      driver: 'json-file'
      options:
        max-size: '5m'
        max-file: '1'
//goto shell\docker\scale\restart.sh
#!/bin/bash
docker-compose --compatibility restart
//goto shell\docker\scale\scale.sh
#!/bin/bash
docker-compose --compatibility up -d --scale nginx=1 --scale demo=3 
//goto shell\docker\scale\stop.sh
#!/bin/bash
docker-compose down
//goto shell\docker\single\docker-compose.yml
version: '3'
services:
  docker-demo:
    image: registry.cn-shanghai.aliyuncs.com/00fly/docker-demo:0.0.1
    container_name: docker-demo
    deploy:
      resources:
        limits:
          cpus: '0.80'
          memory: 300M
        reservations:
          cpus: '0.05'
          memory: 100M
    ports:
    - 80:8080
    restart: on-failure
    logging:
      driver: json-file
      options:
        max-size: 5m
        max-file: '1'
//goto shell\docker\single\restart.sh
#!/bin/bash
docker-compose down && docker system prune -f && docker-compose up -d
//goto shell\docker\single\stop.sh
#!/bin/bash
docker-compose down
//goto shell\init.sh
#!/bin/bash
dos2unix *
dos2unix */*
dos2unix */*/*

chmod +x *.sh
chmod +x */*.sh
//goto shell\reload-jar.sh
#!/bin/bash
# get pid

pname="springboot-cache.jar"
echo  -e  "jar-name=$pname\r\n"


get_pid(){
 pid=`ps -ef | grep $pname | grep -v grep | awk '{print $2}'`
 echo "$pid"
}

ps -ef|grep $pname

PID=$(get_pid)
if [ -z "${PID}" ] 
then
 echo -e "\r\nJava Application already stop!"
else
 echo -e '\r\nkill -9  '${PID} '\r\n'
 kill -9 ${PID}
 echo -e "Java Application is stop!"
fi

rm -rf info.log

echo -e "\r\nJava Application will startup!\r\n"
jar_path=`find .. -name $pname`

#echo "jarfile=$jar_path"

nohup java -jar $jar_path --server.port=8181 >>./info.log 2>&1 &

ps -ef|grep $pname
//goto shell\reload-war.sh
#!/bin/bash
# get pid
get_pid(){
 pname="docker-demo.war"
 pid=`ps -ef | grep $pname | grep -v grep | awk '{print $2}'`
 echo "$pid"
}

ps -ef|grep docker-demo.war

PID=$(get_pid)
if [ -z "${PID}" ] 
then
 echo -e "\r\nJava Application already stop!"
else
 echo -e '\r\nkill -9  '${PID}
 kill -9 ${PID}
 echo -e "Java Application is stop!"
fi

rm -rf info.log

echo -e "\r\nJava Application will startup!"
nohup java -jar /work/demo/web/docker-demo.war -Xms64m -Xmx64m --server.port=8181 >>./info.log 2>&1 &
#sleep 2s
#nohup java -jar /work/demo/web/docker-demo.war -Xms64m -Xmx64m --server.port=8182 >>./info.log 2>&1 &

ps -ef|grep docker-demo.war

echo -e "please visit: https://test.00fly.online/user/"

#tail -f info.log
//goto shell\start-service.sh
#!/bin/bash 
java -jar docker-demo.war -Xms64m -Xmx64m --server.port=8083 &
//goto src\main\java\com\fly\common\AnnotationHelper.java
package com.fly.common;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import lombok.extern.slf4j.Slf4j;

/**
 * 
 * 注解处理工具类
 * 
 * @author 00fly
 * @version [版本号, 2020-04-16]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Slf4j
public class AnnotationHelper
{
    private static List<String> cacheList = new ArrayList<>();
    
    private AnnotationHelper()
    {
        super();
    }
    
    /**
     * 得到类上面的注解信息
     * 
     * @param scannerClass
     * @param allowInjectClass
     * @return
     */
    private static Annotation getClassAnnotation(Class<?> scannerClass, Class<? extends Annotation> allowInjectClass)
    {
        if (!scannerClass.isAnnotationPresent(allowInjectClass))
        {
            return null;
        }
        return scannerClass.getAnnotation(allowInjectClass);
    }
    
    /**
     * 使用Java反射得到注解的信息
     * 
     * @param annotation
     * @param methodName
     * @return Exception
     */
    private static Object getAnnotationInfo(Annotation annotation, String methodName)
        throws Exception
    {
        if (annotation == null)
        {
            return null;
        }
        Method declaredMethod = annotation.getClass().getDeclaredMethod(methodName, null);
        return declaredMethod.invoke(annotation, null);
    }
    
    /**
     * 从上下文获取 Controller注解类的 RequestMapping注解url信息
     * 
     * @param applicationContext
     * @return
     * @throws Exception
     * @see [类、类#方法、类#成员]
     */
    public static List<String> getRequestMappingURL(ApplicationContext applicationContext)
        throws Exception
    {
        if (cacheList.isEmpty())
        {
            synchronized (AnnotationHelper.class)
            {
                List<String> list = new ArrayList<>();
                Map<String, Object> map = applicationContext.getBeansWithAnnotation(Controller.class);
                for (String key : map.keySet())
                {
                    Class<?> clazz = map.get(key).getClass();
                    Annotation classAnnotation = getClassAnnotation(clazz, RequestMapping.class);
                    Object object = getAnnotationInfo(classAnnotation, "value");
                    if (object != null)
                    {
                        String[] array = (String[])object;
                        log.info("{} -> {}", clazz.getName(), object);
                        for (String it : array)
                        {
                            if (!it.contains("$"))
                            {
                                list.add(it);
                            }
                        }
                    }
                }
                cacheList = list;
            }
        }
        return cacheList;
    }
}
//goto src\main\java\com\fly\common\AuthorizationInterceptor.java
package com.fly.common;

import java.net.InetAddress;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

/**
 * 
 * AuthorizationInterceptor
 * 
 * @author 00fly
 * @version [版本号, 2019年7月21日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Component
public class AuthorizationInterceptor extends HandlerInterceptorAdapter
{
    @Autowired
    ApplicationContext applicationContext;
    
    @Value("${server.port}")
    String port;
    
    @Autowired
    HttpSession session;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception
    {
        if (session.getAttribute("urls") == null)
        {
            session.setAttribute("urls", AnnotationHelper.getRequestMappingURL(applicationContext));
            session.setAttribute("port", port);
            session.setAttribute("ip", InetAddress.getLocalHost().getHostAddress());
        }
        return true;
    }
}
//goto src\main\java\com\fly\common\WebMvcConfig.java
package com.fly.common;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 
 * WebMvcConfig
 * 
 * @author 00fly
 * @version [版本号, 2019年7月21日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer
{
    @Autowired
    private AuthorizationInterceptor authorizationInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry)
    {
        registry.addInterceptor(authorizationInterceptor).addPathPatterns("/user/**");
    }
}
//goto src\main\java\com\fly\demo\model\User.java
package com.fly.demo.model;

import java.io.Serializable;

import lombok.Data;
import org.hibernate.validator.constraints.Range;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Data
public class User implements Serializable
{
    private static final long serialVersionUID = -4621975403168327735L;
    
    private Long userId;
    
    @NotBlank(message = "用户名不能为空")
    private String userName;
    
    @NotNull(message = "年龄不能为空")
    @Range(min = 10, max = 60, message = "年龄必须在{min}-{max}")
    private Integer age;
    
    private String desc;
}
//goto src\main\java\com\fly\demo\service\impl\UserServiceImpl.java
package com.fly.demo.service.impl;

import java.util.List;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.RandomUtils;
import org.springframework.stereotype.Service;

import com.fly.demo.model.User;
import com.fly.demo.service.UserService;
import com.google.common.collect.Lists;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class UserServiceImpl implements  UserService
{
    private List<User> users = Lists.newArrayList();
    
    private Long sequence = 1L;
    
    /**
     * 初始化
     * 
     * @see [类、类#方法、类#成员]
     */
    @PostConstruct
    public void init()
    {
        log.info("PostConstruct users");
        for (int i = 0; i < 5; i++)
        {
            User user = new User();
            user.setUserId(sequence);
            user.setUserName("user_" + sequence);
            user.setAge(RandomUtils.nextInt(10, 40));
            user.setDesc("This is a user " + sequence);
            users.add(user);
            sequence++;
        }
    }
    
    private void insert(User user)
    {
        log.info("insert user : {}", user);
        user.setUserId(sequence + 1);
        users.add(user);
        sequence++;
    }
    
    private void update(User user)
    {
        log.info("update user id = {}", user.getUserId());
        for (User it : users)
        {
            if (it.getUserId().equals(user.getUserId()))
            {
                it.setUserName(user.getUserName());
                it.setAge(user.getAge());
                it.setDesc(user.getDesc());
                return;
            }
        }
    }
    
    /**
     * 新增/根据id更新
     * 
     * @param user
     * @see [类、类#方法、类#成员]
     */
    @Override
    public void saveOrUpdate(User user)
    {
        if (user.getUserId() != null)
        {
            update(user);
            return;
        }
        insert(user);
    }
    
    @Override
    public void delete(Long userId)
    {
        log.info("delete user id = {}", userId);
        for (User user : users)
        {
            if (user.getUserId().equals(userId))
            {
                users.remove(user);
                return;
            }
        }
    }
    
    @Override
    public User get(Long userId)
    {
        log.info("get user id = {}", userId);
        for (User user : users)
        {
            if (user.getUserId().equals(userId))
            {
                return user;
            }
        }
        return null;
    }
    
    @Override
    public List<User> list()
    {
        log.info("list users");
        return users;
    }
}
//goto src\main\java\com\fly\demo\service\UserService.java
package com.fly.demo.service;

import java.util.List;

import com.fly.demo.model.User;

public interface UserService
{
    void saveOrUpdate(User user);
    
    void delete(Long userId);
    
    User get(Long userId);
    
    List<User> list();
    
}
//goto src\main\java\com\fly\demo\web\IndexController.java
package com.fly.demo.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import com.fly.common.AnnotationHelper;

/**
 * 
 * IndexController
 * 
 * @author 00fly
 * @version [版本号, 2020-04-16]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Controller
public class IndexController
{
    @Autowired
    ApplicationContext applicationContext;
    
    /**
     * 首页
     * 
     * @param model
     * @return
     * @throws Exception
     * @see [类、类#方法、类#成员]
     */
    @GetMapping("/")
    public String index(Model model)
        throws Exception
    {
        model.addAttribute("urls", AnnotationHelper.getRequestMappingURL(applicationContext));
        return "/index";
    }
}
//goto src\main\java\com\fly\demo\web\UserApi.java
package com.fly.demo.web;

import javax.validation.Valid;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import com.fly.demo.model.User;
import com.fly.demo.service.UserService;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("/user")
public class UserApi
{
    @Autowired
    private UserService userService;
    
    /**
     * 测试添加缓存,后续读取从缓存中取
     * 
     * @param userId
     * @return
     * @see [类、类#方法、类#成员]
     */
    @GetMapping("get")
    public User get(Long userId)
    {
        return userService.get(userId);
    }
    
    /**
     * 新增/更新数据
     * 
     * @param user
     * @return
     * @see [类、类#方法、类#成员]
     */
    @PostMapping("/add")
    public String add(@Valid @ModelAttribute("item") User user, Errors errors, Model model)
    {
        if (errors.hasErrors())
        {
            StringBuilder errorMsg = new StringBuilder();
            for (ObjectError error : errors.getAllErrors())
            {
                errorMsg.append(error.getDefaultMessage()).append(" ");
            }
            if (errorMsg.length() > 0)
            {
                log.info("errors message={}", errorMsg);
            }
            model.addAttribute("items", userService.list());
            return "/user/show";
        }
        userService.saveOrUpdate(user);
        return "redirect:/user/list";
    }
    
    /**
     * 测试删除缓存
     */
    @GetMapping("/delete/{id}")
    public String delete(@PathVariable Long id)
    {
        userService.delete(id);
        return "redirect:/user/list";
    }
    
    @GetMapping({"/", "/list"})
    public String list(Model model)
    {
        User user = new User();
        if (RandomUtils.nextInt(1, 10) > 1)
        {
            user.setUserName(RandomStringUtils.randomNumeric(5));
            user.setAge(RandomUtils.nextInt(10, 70));
            user.setDesc(RandomStringUtils.randomNumeric(5));
        }
        model.addAttribute("item", user);
        model.addAttribute("items", userService.list());
        return "/user/show";
    }
    
    /**
     * 编辑数据
     * 
     * @param id
     * @param model
     * @return
     * @see [类、类#方法、类#成员]
     */
    @GetMapping("/update/{id}")
    public String update(@PathVariable Long id, Model model)
    {
        model.addAttribute("item", userService.get(id));
        model.addAttribute("items", userService.list());
        return "/user/show";
    }
}
//goto src\main\java\com\fly\DemoBootApplication.java
package com.fly;

import java.net.InetAddress;

import org.apache.commons.lang3.SystemUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@SpringBootApplication
public class DemoBootApplication
{
    @Value("${server.port}")
    Integer port;
    
    public static void main(String[] args)
    {
        SpringApplication.run(DemoBootApplication.class, args);
    }
    
    @Bean
    @ConditionalOnWebApplication
    CommandLineRunner openBrowser()
    {
        return args -> {
            if (SystemUtils.IS_OS_WINDOWS && port > 0)
            {
                log.info("★★★★★★★★  now open Browser ★★★★★★★★ ");
                String ip = InetAddress.getLocalHost().getHostAddress();
                String url = "http://" + ip + ":" + port;
                Runtime.getRuntime().exec("cmd /c start /min " + url);
            }
        };
    }
}
//goto src\main\resources\application.yml
server:
  port: 8080
spring:
  mvc:
    view:
      prefix: /WEB-INF/views
      suffix: .jsp
//goto src\main\webapp\WEB-INF\views\index.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<table>
	<tr>
		<th colspan="${fn:length(urls)+1}">Navigate</th>
	</tr>
	<tr>
		<c:forEach var="item" items="${urls}">
			<td><a href="${pageContext.request.contextPath}${item}/">${item}</a></td>
		</c:forEach>
	</tr>
</table>
//goto src\main\webapp\WEB-INF\views\user\show.jsp
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<meta charset="utf-8">
<html>
<head>
<title>00fly功能演示</title>
<style>
body {
	margin: 10;
	font-size: 62.5%;
	line-height: 1.5;
}

.blue-button {
	background: #25A6E1;
	padding: 3px 20px;
	color: #fff;
	font-size: 12px;
	border-radius: 2px;
	-moz-border-radius: 2px;
	-webkit-border-radius: 4px;
	border: 1px solid #1A87B9
}

table {
	width: 70%;
}

th {
	background: SteelBlue;
	color: white;
}

td, th {
	border: 1px solid gray;
	font-size: 12px;
	text-align: left;
	padding: 5px 10px;
	overflow:hidden; 
	white-space:nowrap; 
	text-overflow:ellipsis;
	max-width: 200px;
}
</style>
</head>
<script type="text/javascript">
	function formReset() {
		location.href="/user/list";
	}
</script>
<body>
	<center>
    <table>
	  <tr>
		<th colspan="${fn:length(urls)+1}">Navigate</th>
	  </tr>
	  <tr>
		<c:forEach var="item" items="${urls}">
			<td><a href="${pageContext.request.contextPath}${item}/">${item}</a></td>
		</c:forEach>
	  </tr>
    </table>    
	<form:form method="post" modelAttribute="item" action="${pageContext.request.contextPath}/user/add">
		<table>
			<tr>
				<th colspan="3">Add or Edit Item</th>
				<form:hidden path="userId" />
			</tr>
			<tr>
				<td><form:label path="userName">userName:</form:label></td>
				<td><form:input path="userName" size="30" maxlength="30"></form:input></td>
				<td>String <form:errors path="userName" cssStyle="color:red" /></td>
			</tr>
			<tr>
				<td><form:label path="age">age:</form:label></td>
				<td><form:input path="age" size="30" maxlength="30"></form:input></td>
				<td>Integer <form:errors path="age" cssStyle="color:red" /></td>
			</tr>
			<tr>
				<td><form:label path="desc">desc:</form:label></td>
				<td><form:input path="desc" size="30" maxlength="30"></form:input></td>
				<td>String <form:errors path="desc" cssStyle="color:red" /></td>
			</tr>
			<tr>
				<td colspan="3" style="text-align: center;"><input type="submit" class="blue-button" /> <input type="reset" class="blue-button" onclick="formReset()" /></td>
			</tr>
		</table>
	</form:form>
	<h3>Data List</h3>
	<c:if test="${!empty items}">
		<table>
			<tr>
				<th width="5">序号</th>
				<th width="5">Edit</th>
				<th width="5">Delete</th>
				<th width="100">userId</th>
				<th width="150">userName</th>
				<th width="150">age</th>
				<th width="150">desc</th>
			</tr>
			<c:forEach items="${items}" var="it" varStatus="vs">
				<tr>
					<td>${vs.count}</td>
					<td><a href="<c:url value='/user/update/${it.userId}' />">Edit</a></td>
					<td><a href="<c:url value='/user/delete/${it.userId}' />">Delete</a></td>
					<td>${it.userId}</td>
					<td>${it.userName}</td>
					<td>${it.age}</td>
					<td>${it.desc}</td>
				</tr>
			</c:forEach>
		</table>
	</c:if>
	<h3>
		应用端口:<font color="red">${port}</font>
	</h3>
	<h3>
		Server IP<font color="red">${ip}</font>
	</h3>
	</center>
</body>
</html>

三,准备工作

1. pom.xml 引入组件

		<!-- JSTL 支持,按需引入 -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
		</dependency>

		<!-- JSP 编译支持,必须引入-->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
			<scope>provided</scope>
		</dependency>

2. application.yml 指定jsp配置

application.yml

spring:
  mvc:
    view:
      prefix: /WEB-INF/views
      suffix: .jsp

四,war方式运行

1. 修改pom.xml文件

	<packaging>war</packaging>

2. mvn执行打包

mvn clean package

执行后会在target目录生成war包,拷贝出来后运行

java -jar docker-demo-0.0.1.war

浏览器访问: http://127.0.0.1:8080/user/ 界面如下:
在这里插入图片描述

五,jar方式运行

复制 pom.xml重命名为 pom-jsp-jar.xml

1. 修改pom-jsp-jar.xml文件

	<packaging>jar</packaging>

2. 修改 spring-boot-maven-plugin添加版本号

注意只能使用1.4.2.RELEASE,其他版本不行

			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<version>1.4.2.RELEASE</version>
			</plugin>

3. 添加资源文件配置(Jar运行必须

		<resources>
			<resource>
				<directory>src/main/java</directory>
				<excludes>
					<exclude>**/*.java</exclude>
				</excludes>
			</resource>
			<resource>
				<directory>src/main/resources</directory>
				<includes>
					<include>**/**</include>
				</includes>
			</resource>
			<resource>
				<directory>src/main/webapp</directory>
				<includes>
					<include>**/**</include>
				</includes>
				<targetPath>META-INF/resources</targetPath>
			</resource>
		</resources>

4. mvn执行打包

mvn clean package -f pom-jsp-jar.xml

执行后会在target目录生成 jar包,拷贝出来后运行

java -jar docker-demo-0.0.1.jar

六,war、jar配置文件区别

在这里插入图片描述
在这里插入图片描述


有任何问题和建议,都可以向我提问讨论,大家一起进步,谢谢!

-over-

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/339051.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

表白墙网站PHP源码,支持封装成APP

源码介绍 PHP表白墙网站源码&#xff0c;适用于校园内或校区间使用&#xff0c;同时支持封装成APP。告别使用QQ空间的表白墙。 简单安装&#xff0c;只需PHP版本5.6以上即可。 通过上传程序进行安装&#xff0c;并设置账号密码&#xff0c;登录后台后切换模板&#xff0c;适配…

HCIA——21C/S、P2P、peer的选择

学习目标&#xff1a; 计算机网络 1.掌握计算机网络的基本概念、基本原理和基本方法。 2.掌握计算机网络的体系结构和典型网络协议&#xff0c;了解典型网络设备的组成和特点&#xff0c;理解典型网络设备的工作原理。 3.能够运用计算机网络的基本概念、基本原理和基本方法进行…

Java面试题50道

文章目录 1.谈谈你对Spring的理解2.Spring的常用注解有哪些3.Spring中的bean线程安全吗4.Spring中的设计模式有哪些5.Spring事务传播行为有几种6.Spring是怎么解决循环依赖的7.SpringBoot自动配置原理8.SpringBoot配置文件类型以及加载顺序9.SpringCloud的常用组件有哪些10.说一…

Debian11下编译ADAravis和Motor模块的一条龙过程

Debian11编译EPICS ADAravis记录 一年前整理的上面文&#xff0c;这几天重新走了一遍&#xff0c;有些地方会碰到问题&#xff0c;需要补充些环节&#xff0c;motor模块以前和areaDetector一条龙编译时&#xff0c;总是有问题&#xff0c;当时就没尝试了&#xff0c;这几天尝试…

C#串口通讯控制4路继电上位机

C#串口通讯控制4路继电上位机 界面如下 源码如下 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text;//引入空间 using System.Windows.Forms; using System.I…

通过Stable Diffusion生成虚假的遥感影像

简介 这两天玩了一下stable diffusion&#xff0c;是真的好玩&#xff01; 然后我在想遥感有没有相关的生成模型&#xff0c;找了一下&#xff0c;还真找到了&#xff08;https://github.com/xiaoyuan1996/Stable-Diffusion-for-Remote-Sensing-Image-Generation/tree/main&a…

spark 入门教程

一、安装scala环境 官网下载地址 Download | The Scala Programming Language,本次使用版本为sacla2.11.12,将压缩包解压至指定目录&#xff0c;配置好环境变量&#xff0c;控制台验证是否安环境是否可用&#xff1a; 二、添加pom依赖 创建一个maven项目 1、添加scala的sdk依…

详细分析Java中Service报NullPointerException的相关知识(实战Bug)

目录 前言1. 问题所示2. 基本知识3. 原理分析 前言 在Java中&#xff0c;NullPointerException是一种常见的运行时异常&#xff0c;通常发生在尝试访问或操作一个空对象引用&#xff08;null reference&#xff09;时 1. 问题所示 在操作代码的时候&#xff0c;浏览器报服务…

Mysql - 定点型(DECIMAL)的使用详解及练习

目录 &#x1f436;1. 前言&#xff1a; &#x1f436;2. DECIMAL类型简介 &#x1f436;3. Decimal使用实战 &#x1f96a;#结论1&#xff1a;小数位不足会自动补0 &#x1f96a;#结论2&#xff1a;小数位超出会截断 并按四舍五入处理。 &#x1f96a;#结论3&#xff1…

数据结构实验7:查找的应用

目录 一、实验目的 二、实验原理 1. 顺序查找 2. 折半查找 3. 二叉树查找 三、实验内容 实验一 任务 代码 截图 实验2 任务 代码 截图 一、实验目的 1.掌握查找的基本概念&#xff1b; 2.掌握并实现以下查找算法&#xff1a;顺序查找、折半查找、二叉树查找。 …

2.RHCSA启动配置

rht-clearcourse 0 #重置练习环境 rht-setcourse rh134 #切换CSA练习环境 cat /etc/rht #查看当前环境 virt-manager #打开KVM控制台 rht-vmctl start classroom #必做&#xff0c;start all不会包含classroom&#xff0c;需…

【Linux】Ubuntu的gnome切换KDE Plasma

文章目录 安装KDE Plasma桌面环境添加软件源并更新apt安装kubuntu-desktop&#xff08;作者没有成功&#xff09;aptitude安装kubuntu-desktop多次aptitude install&#xff08;特别重要特别重要&#xff09;其他kde软件包 卸载gnome桌面 Ubuntu自带的桌面环境是gnome&#xff…

PSoc62™开发板之rtc时间获取

实验目的 1.使用PSoc62™芯片读取内部rtc时间 2.OLED屏幕显示当前时间戳 实验准备 PSoc62™开发板SSD1306 OLED模块公母头杜邦线 芯片资源 PSoC 6系列MCU时钟系统由以下几部分组成&#xff0c;PSoc62™开发板没有接外部时钟源&#xff0c;所以只能从IMO、ILO、PILO里边配…

EtherNet/IP开发:C++搭建基础模块,EtherNet/IP源代码

这里是CIP资料的协议层级图&#xff0c;讲解协议构造。 ODVA&#xff08;www.ODVA.org&#xff09;成立于1995年&#xff0c;是一个全球性协会&#xff0c;其成员包括世界领先的自动化公司。结合其成员的支持&#xff0c;ODVA的使命是在工业自动化中推进开放、可互操作的信息和…

SQL注入实战:Update注入

一&#xff1a;Update注入原理 有的程序员在写源代码的时候&#xff0c;只是对查询的sql语句的用户输入内容进行了过滤&#xff0c;忽略了update 类型sql语句的用户输入的内容的过滤 二、mysql的Update语句复习 update语句可用来修改表中的数据&#xff0c;简单来说基本的使…

算法每日一题: 分割数组的最大值 | 动归 | 分割数组 | 贪心+二分

Hello&#xff0c;大家好&#xff0c;我是星恒 呜呜呜&#xff0c;今天给大家带来的又是一道经典的动归难题。 题目&#xff1a;leetcode 410给定一个非负整数数组 nums 和一个整数 k &#xff0c;你需要将这个数组分成 k_ 个非空的连续子数组。设计一个算法使得这 k _个子数组…

51单片机电子密码锁Proteus仿真+程序+视频+报告

目录 视频 设计分析 系统结构 仿真图 资料内容 资料下载地址&#xff1a;51单片机电子密码锁Proteus仿真程序视频报告 视频 单片机电子密码锁Proteus仿真程序视频 设计分析 (1)能够从键盘中输入密码&#xff0c;并相应地在显示器上显示‘*’&#xff1b; (2)能够判断密码…

反序列化字符串逃逸(上篇)

首先&#xff0c;必须先明白&#xff0c;这个点并不难&#xff0c;我给大家梳理一遍就会明白。 反序列化字符串逃逸就是序列化过程中逃逸出来字符&#xff0c;是不是很简单&#xff0c;哈哈哈&#xff01; 好了&#xff0c;不闹了&#xff0c;其实&#xff1a; 这里你们只要懂…

【C++ | 数据结构】从哈希的概念 到封装C++STL中的unordered系列容器

文章目录 一、unordered系列容器的底层结构 - 哈希1. 哈希概念2. 哈希冲突 二、解决哈希冲突方法一&#xff1a;合理设计哈希函数&#x1f6a9;哈希函数设计原则&#x1f6a9;常见哈希函数 方法二&#xff1a;开闭散列&#x1f6a9;闭散列线性探测法&#xff08;实现&#xff0…

Linux操作系统——理解文件系统

预备知识 到目前为止&#xff0c;我们所学习到的关于文件的操作&#xff0c;全部都是基于文件被打开&#xff0c;被访问&#xff0c;访问期间比较重要的有重定向&#xff0c;缓冲区&#xff0c;一切皆文件&#xff0c;当我们访问完毕的时候需要将文件关闭&#xff0c;关闭时那…