写于开始
我之前没有学过java,用java开发Web应用程序更没有接触过,但我不是软件开发领域的小白,所以我决定试试。有经验的Web开发者都明白学习一种语言、一种框架只要搞懂下面几个问题就算入门了。
环境如何配置
环境主要是指开发环境和运行环境,一要方便自己本地开发调试,二要会配置程序的运行环境。
程序如何路由
路由包括页面路由和Ajax路由,如何从一个页面跳转到另一个页面,Ajax请求如何从前台走到后台。
程序如何与数据库交互
程序如何在后台从数据库中读写数据,如何实现低耦合。
程序如何展示数据
从后台返回数据后如何展示,现在有很多独立的前端框架,比如Vue、Angular等等。
程序如何安装部署
像php、js都是解释执行的语言,不存在编译打包发布,但像java、C#都是编译执行的语言,需要编译打包发布到服务器上执行,还要考虑到混淆加密。
SSM框架
在java web开发领域SSM框架(Spring + SpringMVC + MyBatis)应该算是鼎鼎有名的了,我们就来看看SSM框架是如何解决上面提出的那些个问题。
Spring 框架是一个分层架构,由 7 个定义良好的模块组成(核心容器、Spring 上下文、Spring AOP、Spring DAO、Spring ORM、Spring Web 模块、Spring MVC 框架)。Spring模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式。其核心就是IOC 和 AOP,如何实现靠的就是beans包。bean是什么我们先点到为止,以后还会讲到。
SpringMVC是分离了控制器、模型对象、分派器以及处理程序对象的框架,这种分离让它们更容易进行定制、更加灵活、更加容易扩展。
MyBatis是一个支持普通SQL查询,存储过程和高级映射的半自动化持久层框架,为什么是半自动化后面会讲到,我觉得这也是它足够灵活的所在。
在开始之前我们先来个小插曲,介绍一个小工具Maven,Maven除了有不俗的程序构建能力之外,还是一个非常高级的项目管理工具,做过php开发的应该都知道Composer,Maven和Composer有点像可以很好的管理项目中用到各种组件包,而且还可以做项目的测试、编译、发布等,对于JavaWeb开发来说是一个非常实用的工具。
环境配置
运行环境有tomcat和jdk就行,把环境变量配置好。开发环境我选用的是IDEA,没有什么原因个人爱好而已,什么IDE都行习惯就好。
新建项目时选择Maven,我们要用它来管理我们的程序,然后配置pom.xml文件,这是Maven的包管理包管理文件,配置好后会自动下载所依赖的包(javaee、springframework、mybatis等),我把我的pom.xml贴出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
| <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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>gamma</groupId> <artifactId>edu</artifactId> <packaging>war</packaging> <version>1.0</version> <name>edu Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <spring.version>5.0.1.RELEASE</spring.version> <fastjson.version>1.2.40</fastjson.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency>
<dependency> <groupId>javaee</groupId> <artifactId>javaee-api</artifactId> <version>5</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency>
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency>
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency>
<dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.22.0-GA</version> </dependency>
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${fastjson.version}</version> </dependency>
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version> </dependency>
<dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.5</version> </dependency>
<dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency>
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.44</version> </dependency>
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.2</version> </dependency>
<dependency> <groupId>com.github.jsqlparser</groupId> <artifactId>jsqlparser</artifactId> <version>1.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.5</version> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.44</version> </dependency> </dependencies> <configuration> <overwrite>true</overwrite> </configuration> </plugin> </plugins> <finalName>edu</finalName> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/resources</directory> </resource> </resources> </build> </project>
|
这个文件就是包管理文件,开发中用到的包都通过它来加载、管理。
接下来在src/main目录下新建java目录,这是源代码目录,Controller、Model、DAO、Service都在这个目录下。
还要在src目录下建立test目录,然后在test下再建立java,这个目录是写单元测试代码的目录。
在src/main目录下还有一个resources目录,这里是放置配置文件的地方,常见的配置文件有:applicationContext.xml、mybatis-config.xml、dispatcher-servlet.xml等
在src/main目录下还有一个webapp目录,这个目录是用来放置jsp(WEB-INF)和静态资源(resources)的目录,WEB-INF下的web.xml就是容器的入口文件,所有的资源都从这里加载到Spring容器当中去,index.jsp是程序的入口文件。你可以在WEB-INF目录下建立jsp文件夹,用来放置自己的jsp文件。
关于运行,你可以通过Run菜单配置一个Tomcat服务器,就可以本地运行了。具体如何配置百科一下就知道了。
关于Bean
那么Bean到底是个什么东西,前面我们说过Bean是Spring的核心,Spring就像一个大工厂,Spring容器中的Bean就是工厂里的产品,Spring工厂可以生产什么产品,取决于配置文件中如何配置Bean。
对于我们而言,我们使用Spring框架所做的就是两件事:开发Bean、配置Bean。对于Spring来说,它要做的就是根据配置文件来创建Bean实例,并调用Bean实例的方法完成“依赖注入”。
开发Bean,就是把写好的java代码加上诸如@Controller、@Component、 @Repository、@Service 、@Configration这些注解,把要实例化的对象转化成一个Bean,放在IoC容器中,等你要用的时候,可以直接调用。
使用Bean,就是在需要使用实例化的对象的地方加上诸如@Autowired 、@Resource把Ioc容器中的Bean拿出来组装完成实例化。
Bean的配置方法有三种:基于xml配置Bean(手动配置)、使用注释定义Bean(自动扫描)、基于java类提供的Bean定义。
路由配置
我先贴出我的dispatcher-servlet.xml文件,里面放的有路由配置信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd "> <context:component-scan base-package="cn.jpp"/> <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/plain;charset=UTF-8</value> <value>text/html;charset=UTF-8</value> <value>application/json;charset=UTF-8</value> <value>application/x-www-form-urlencoded;charset=UTF-8</value> <value>*/*;charset=UTF-8</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven> <mvc:resources location="/resources/" mapping="/resources/**"/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"></property> <property name="suffix" value=".jsp"></property> </bean> </beans>
|
这个里面有两个核心的标签component-scan和annotation-driven。
component-scan会自动扫描base-package包下的所有文件,并自动转换成Bean,加载到Spring的容器中来,以备调用。要想让component-scan扫描到Controller,需要在Controller类上加@Controller注释。
我举两个例子,http://localhost:8080/hello/get.do(ajax请求),会自动走到下面的Controller里去。
1 2 3 4 5 6 7 8 9
| @Controller @RequestMapping("/hello") public class UserInfoController { @RequestMapping(value = "get.do") public String getData(){ return 'hello'; } }
|
http://localhost:8080/hello/say(页面跳转),会自动走到下面的Controller里去,并跳转到say.jsp页面。
1 2 3 4 5 6 7 8 9 10 11 12
| @Controller @RequestMapping("/hello") public class ViewController { @RequestMapping(value = "say") public ModelAndView hello(HttpServletRequest request, HttpServletResponse resp) throws Exception { ModelAndView mv = new ModelAndView(); mv.addObject("message", "Hello World!"); mv.setViewName("say"); return mv; } }
|
annotation-driven的作用是自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter,这两个bean是SpringMVC为@Controllers分发请求所必须的。并提供了:数据绑定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,读写XML的支持(JAXB),读写JSON的支持(Jackson)。后面,我们处理响应ajax请求时,就使用到了对json的支持。
持久层配置
老规矩,我先贴配置文件(applicationContext.xml、mybatis-config.xml)。
applicationContext.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://xxx:3306/test?useUnicode=true&characterEncoding=UTF-8"></property> <property name="user" value="root"></property> <property name="password" value="xxx"></property> </bean> <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:mybatis-config.xml"></property> <property name="dataSource" ref="dataSource"></property> <property name="mapperLocations" value="classpath:cn/jpp/dao/**/*.xml"/> <property name="plugins"> <array> <bean id="page" class="com.github.pagehelper.PageInterceptor"> <property name="properties"> <value> helperDialect=mysql </value> </property> </bean> </array> </property> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="sessionFactory"></property> <property name="basePackage" value="cn.jpp.dao"></property> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
|
mybatis-config.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <setting name="jdbcTypeForNull" value="NULL"/> <setting name="useGeneratedKeys" value="true"/> <setting name="lazyLoadingEnabled" value="true"/> <setting name="logImpl" value="STDOUT_LOGGING" /> </settings> <typeAliases> <package name="cn.jpp.entity"/> </typeAliases> <mappers> </mappers> </configuration>
|
我的cn.jpp.dao包
定义UserinfoMapper接口
1 2 3 4 5
| @Repository public interface UserinfoMapper { int insert(Userinfo record); List<Userinfo> getUsers(); }
|
UserinfoMapper.xml,它是UserinfoMapper接口的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?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="cn.jpp.dao.UserinfoMapper"> <insert id="insert" parameterType="cn.jpp.entity.Userinfo"> insert into userinfo (name, age, role_id) values (#{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER}, #{roleId,jdbcType=INTEGER}) </insert> <select id="getUsers" resultMap="ClassResultMap"> SELECT u.id AS userId,u.name AS userName,u.age AS userAge,r.name AS roleName FROM userinfo u ,role r WHERE u.role_id = r.id </select> <resultMap id="ClassResultMap" type="cn.jpp.entity.Userinfo"> <id column="userId" jdbcType="INTEGER" property="id"/> <result column="userName" jdbcType="VARCHAR" property="name"/> <result column="userAge" jdbcType="INTEGER" property="age"/> <association property="role" javaType="cn.jpp.entity.Role" resultMap="RoleResult"></association> </resultMap> <resultMap id="RoleResult" type="cn.jpp.entity.Role"> <result property="name" jdbcType="VARCHAR" column="roleName"/> </resultMap> </mapper>
|
我的cn.jpp.service包
定义服务接口IUserInfoServcie
1 2 3 4
| public interface IUserInfoService { void add(Userinfo user); List<Userinfo> getUsers(); }
|
定义服务接口的实现IUserInfoServcieLmpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Service public class UserInfoServiceLmpl implements IUserInfoService {
@Autowired private UserinfoMapper userMapper;
public void add(Userinfo user) { userMapper.insert(user); }
public List<Userinfo> getUsers() { PageHelper.startPage(1, 20); List<Userinfo> list = userMapper.getUsers(); List<Userinfo> pageInfo = new PageInfo<Userinfo>(list).getList(); return pageInfo; } }
|
我的cn.jpp.entity包
定义实体Userinfo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public class Userinfo { private Integer id;
private String name;
private Integer age; private Integer roleId; private Role role;
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
public Role getRole() { return role; }
public void setRole(Role role) { this.role = role; }
public Integer getRoleId() { return roleId; }
public void setRoleId(Integer roleId) { this.roleId = roleId; }
}
|
可以看出,我在DAO包和Service包中定义了两个接口(一个Mapper,一个Service),Mapper接口注释成了@Repository表明这就是数据仓库,而Mapper接口的实现就Mapper.xml文件,我们看到熟悉的SQL语句;Service接口定义了服务的接口,Service的实现接口被注释成了@Service,私有变量userMapper被注释成了@Autowired表明我要在这里实例化一个对象,这些都会被加载到Spring的容器当中。为什么说MyBatis是一个半自动化的ORM框架就在这里,它的每一步都需要手动标注或配置,当然这也给了我们最大的灵活度,我们不必太多关心他们之间是怎么调用的,只需要关心单个切面是怎么实现的就行。而且都是面向接口编程,外部类只需要知道接口就行,不用关心接口实现,极大降低耦合,也符合面向对象的编程思想(面向接口编程、拥抱变化)。
关于发布
最后贴出我的web.xml配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:dispatcher-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
|
源代码
https://github.com/chjw8016/java-web-ssm
写在最后
看到这里,基本上就算可以入门了,其实还有很多东西要学,比如Java语法,SSM框架的其他高级配置,但是现在程序已经可以跑起来了,其他知识可以慢慢补上。
最后给大家留两个链接,帮助大家理解。
Spring整合Mybatis的xml配置
https://www.cnblogs.com/ClassNotFoundException/p/6425558.html
Bean与Spring容器的关系
https://www.cnblogs.com/wuchanming/p/5426746.html
通用分页插件
https://github.com/pagehelper/Mybatis-PageHelper
活到老,学到老,走在路上的程序员…